jQuery nested functions looping twice - javascript

In my limited understanding of jQuery, I don't understand what is happening here.
I have two divs, each with a class of "required". The 1st div contains a set of checkboxes, while the second contains radio buttons. The object is to highlight the appropriate div background if no objects in either set are selected.
The 2nd set, however (the radio buttons), does have a button pre-selected by default, so should never be highlighted.
Here is what is happening:
Both sets are being looped through twice. At the end of the 1st div (checkbox) loop, the div is correctly highlighted. The radio button items are them checked and the default checked button is recognized and that div is not highlighted. Then, the first div items are again gone through. At the end of this - and BEFORE the 2nd div is looped through for the second time, the 2nd div is highlighted. I am assuming that the cause here, even though it is correctly looping through the checkboxes, it is associating them with the id of the radiobuttons. What I need to do is prevent this second loop-through.
$(document).ready(function () {
$('#Submit').click(function () {
$('div.Required', '#JobForm').each(function () {
var FieldName = this.id;
var FieldLength = FieldName.length
var CheckError = true;
$("input:checkbox").each(function () {
if (this.checked) {
CheckError = false;
}
});
if (CheckError) {
ErrorList += FieldName + ' requires a selection\n';
this.style.backgroundColor = "#FFC0C0";
}
CheckError = true;
$("input:radio").each(function () {
if (this.checked) {
CheckError = false;
}
});
if (CheckError) {
ErrorList += FieldName + ' requires a selection\n';
this.style.backgroundColor = "#FFC0C0";
}
});
if (Error) {
$('#Submit').val('Submit');
alert(ErrorList)
return false;
} else {
document.JobForm.submit();
}
});
});
Thanks to adeneo's suggestions, I was able to limit the double div looping, which also allowed me to eliminate the additional error message. As adeneo stated, since there are two div's, as originally written, the code was looping through both input types each time.
As written below, the first loop loops through the checkboxes, while the second loops through the radio buttons.
$(document).ready(function()
{
$('#Submit').click(function ()
{
$('div.Required','#JobForm').each(function()
{
var FieldName = this.id;
var FieldLength = FieldName.length
var CheckError = true;
$("input:checkbox", this).each(function ()
{
if(this.checked){CheckError=false;}
});
$("input:radio", this).each(function ()
{
if(this.checked){CheckError=false;}
});
if(CheckError){ErrorList += FieldName+' requires a selection\n'; this.style.backgroundColor="#FFC0C0";}
});
if(Error)
{
$('#Submit').val('Submit');
alert(ErrorList)
return false;
}
else
{
document.JobForm.submit();
}
});
});

You're not iterating over each DIV twice, but you're iterating over all the inputs the same number of times as you have matching DIV's
$('#Submit').click(function () {
// loop over the DIV's, lets say two times if there are two elements
$('div.Required', '#JobForm').each(function () {
// ..... other code
// the code below selects all the checkboxes, both times
$("input:checkbox").each(function () {
if (this.checked) {
CheckError = false;
}
});
// the code below selects all the radiobuttons, both times
$("input:radio").each(function () {
if (this.checked) {
CheckError = false;
}
});
// .......more code
});
});
Limit the selection of inputs with context or find()
$("input:checkbox", this).each(function () { ...
or
$(this).find("input:checkbox").each(function () { ...
also, your conditions don't make sense, you keep setting CheckError to a boolean, and on the next line you're checking for that boolean, and you'll never get a different result
CheckError = true;
if (CheckError) { ...
is like doing
if (true) { ...

Related

If statement never returning true when I first hide the element

$('.checkbox').on('change', function() {
$('.pagination').hide();
$('.callout').hide();
$('.checkbox').each(function() {
if ($(this).prop('checked') === true) {
var checkboxName = $(this).val();
$('.callout').each(function() {
var calloutArray = $(this).data();
var i;
for (i = 0; i < calloutArray.category.length; i++) {
$(this).hide();
if (checkboxName === calloutArray.category[i]) {
$(this).show();
}
}
});
}
});
});
To explain this function it basically listens to see if a checkbox has been clicked and then hides all the callouts on the page.
It then loops through each one of those checkboxes and checks which ones are true on the page. I then create a variable that stores the current checkbox value.
After this I then want to loop through each callout and pull its data from a data attribute.
I then loop through each string in the array and hide the callout no matter what. However if the callout has an array value that is the same as the checkbox value then I need to show it.
This seems to be working without the hide. However I need to hide the callouts if they do not hold the same checked category names which is where I'm running into problems.
The If statement seems to never return true if I have already hidden the callout. So the question is how do I show the callout if the selected checkboxes match one of the callout array strings but hide the callout if the string is not in the callout array.
From what I've understand, the following code is equivalent
$('.checkbox').on('change', function () {
$('.pagination, .callout').hide();
$('.checkbox:checked').each(function () {
var checkboxName = $(this).val();
$('.callout').hide().each(function () {
var calloutArray = $(this).data();
if (calloutArray.category.indexOf(checkboxName) !== -1) {
$(this).show();
}
});
});
});
Merge selectors having common actions(hide())
Use :checked pseudo-selector to select only checked elements
Use hide() on selector and then iterate over it using each()
Use indexOf to check if element is in array
You're showing/hiding your element on each iteration of the loop. That means the result of the last iteration wins, as though you hadn't done the earlier ones at all.
You can just use Array#indexOf to see if the name is in the array, and use the resulting flag to show/hide the callout:
$(this).toggle(calloutArray.category.indexOf(checkboxName) != -1);
E.g.:
$('.checkbox').on('change', function() {
$('.pagination').hide();
$('.callout').hide();
$('.checkbox').each(function() {
if ($(this).prop('checked') === true) {
var checkboxName = $(this).val();
$('.callout').each(function() {
var calloutArray = $(this).data();
$(this).toggle(calloutArray.category.indexOf(checkboxName) != -1);
});
}
});
});
Also note that
if ($(this).prop('checked') === true) {
is quite a long way to write
if (this.checked) {
Similarly, with inputelements, this.value is the same as $(this).val().

Why is my jQuery focusout (or blur) event not being fired?

At the bottom of the jsfiddle here, I have this HTML:
<input type="text" id="BLAboxPaymentAmount" value="2">
</br>
<input type="text" id="BLAboxSection5Total" value="3">
..and this jQuery:
$(document).on("focusout", '[id$=boxSection5Total]', function (e) {
var totalvalue = $(this).val();
//alert("boxSection5Total val is " + totalvalue);
var paymenttotalvalue = $('[id$=boxPaymentAmount]').val();
//alert("Payment Total val is " + paymenttotalvalue);
if (totalvalue !== paymenttotalvalue) {
alert("The value in 'Total' does not equal the previous value in 'Payment Total'");
} else {
alert("values ARE equal");
}
});
It works fine in the jsfiddle, but the event is not firing in my Sharepoint page - I enter a value in boxPaymentAmount ("5"), enter another in boxSection5Total ("6"), tab off of boxSection5Total, and I see no alert, as I should, based on this jQuery, which is virtually identical to what's in the jsfiddle:
$(document).on("focusout", '[id$=boxSection5Total]', function (e) {
alert("focusout event has fired");
var totalvalue = $(this).val();
var paymenttotalvalue = $('[id$=boxPaymentAmount]').val();
if (totalvalue !== paymenttotalvalue) {
alert("The value in 'Total' does not equal the previous value in 'Payment Total'");
}
});
So the event is not even being fired - why not?
I ran the page in Chrome and F12d, looking for err msgs in the console, but found none.
UPDATE
For A. (not "The") Wolff:
This is how I create the elements in the code-behind:
boxPaymentAmount = new TextBox
{
CssClass = "dplatypus-webform-field-input"
};
I also changed the "textarea" to "text" in the HTML in the jsfiddle.
UPDATE 2
For Jonathen (not Russell) Crowe:
I changed my jQuery to the following:
$(document).on("blur", "[id$=boxSection5Total]", function (e) {
alert("blur event has fired");
console.log("blur event has fired");
var totalvalue = $(this).val();
var paymenttotalvalue = $('[id$=boxPaymentAmount]').val();
if (totalvalue !== paymenttotalvalue) {
alert("The value in 'Total' does not equal the previous value in 'Payment Total'");
console.log("The value in 'Total' does NOT equal the previous value in 'Payment Total'");
}
else {
console.log("The value in 'Total' DOES equal the previous value in 'Payment Total'");
}
});
...and still see nothing in the console from this event handler.
UPDATE 3
I have many other functions/handlers that fire just fine; so why this one doesn't is a conundrum. Maybe if I show what I've got (eliding some of the gory details), it may shed some light on what's going on (the failing function is the last/at the bottom):
$(document).ready(function () {
console.log('The ready function has been reached; Requester and Payee Status sections should be slid up'); /* This is a "sanity check" so it can be verified that this jQuery script is running/ran */
});
/* NOTE: Things that need to take place after all the elements have been constructed need to go here; the ready function can be too early */
$(window).load(function () {
$('[id$=_AddressRows]').slideUp();
$('[id$=panelSection2]').slideUp();
$('[id$=panelSection3]').slideUp();
$('[id$=ddlPayToVendor]').hide();
});
/* NOTE: this checkbox is only visible if they are not already authenticated; If they select "Yes" (self-identify as UCSC Faculty, Staff, or Student), prompt them to log in */
$(document).on("change", '[id$=ckbxUCSCFacultyStaffOrStudent]', function () {
var ckd = this.checked;
. . . code elided for brevity
});
/* If user selects "payment for self" (they are seeking payment for themselves, as opposed to someone else), omit (invisibilize) sections 2 and 3 on the form TODO: Should I change these from "change" to "click" */
$(document).on("click", '[id$=rbPaymentForSelf]', function () {
if (this.checked) {
. . . code elided for brevity
}
});
/* If user selects "payment for someone else" (they are seeking payment for someone else, as opposed to themselves), make sections 2 and 3 on the form visible */
$(document).on("click", '[id$=rbPaymentForSomeoneElse]', function () {
if (this.checked) {
. . . code elided for brevity
}
});
$(document).on("click", '[id$=rbPaymentToIndividual]', function () {
if (this.checked) {
$('[id$=ddlPayToVendor]').slideUp();
$('[id$=ddlPayToIndividual]').slideDown();
}
});
$(document).on("click", '[id$=rbPaymentToVendor]', function () {
if (this.checked) {
$('[id$=ddlPayToIndividual]').slideUp();
$('[id$=ddlPayToVendor]').slideDown();
}
});
// Refactor this to populate the elements below (description, account codes, tax 1099); may pull from Lists rather than use the hardcoded vals, but if need to do the latter, see http://jsfiddle.net/clayshannon/x8npcpss/3/
$(document).on("change", '[id$=ddlPayToIndividual]', function () {
var value = $(this).val();
. . . code elided for brevity
});
// Refactor this ... (see comment above)
$(document).on("change", '[id$=ddlPayToVendor]', function () {
var value = $(this).val();
. . . code elided for brevity
});
/* Disallow anything other than 0..9 in the "SSN or ITIN" textbox */
$(document).on("keypress", '[id$=txtbxSSNOrITIN]', function (e) {
var k = e.which;
if (k < 48 || k > 57) { e.preventDefault(); }
});
$(document).on("click", '[id$=btnAddFoapalRow]', function (e) {
var textboxHeight = 15;
. . . code elided for brevity
});
$(document).on("keyup", "[id$=explainPaymentTextBox]", function (e) {
console.log("explainPaymentTextBox keyup reached");
while ($(this).outerHeight() < this.scrollHeight + parseFloat($(this).css("borderTopWidth")) + parseFloat($(this).css("borderBottomWidth"))) {
$(this).height($(this).height() + 1);
};
});
HERE IS THE RECALCITRANT ONE (DOESN'T FIRE):
/* Verify that amount in "Total" equals amount in Section 1 "Payment Amount"; this is not working at present; I first tried "focusout" instead of "blur" but neither event fires... */
$(document).on("blur", "[id$=boxSection5Total]", function (e) {
alert("boxSection5Total's blur event has fired");
console.log("boxSection5Total's blur event has fired");
var totalvalue = $(this).val();
var paymenttotalvalue = $('[id$=boxPaymentAmount]').val();
if (totalvalue !== paymenttotalvalue) {
alert("The value in 'Total' does not equal the previous value in 'Payment Total'");
console.log("The value in 'Total' does NOT equal the previous value in 'Payment Total'");
}
else {
console.log("The value in 'Total' DOES equal the previous value in 'Payment Total'");
}
});
Did you try using blur instead of using focusout? The difference between those two events can be found here and, in your case, you only want to capture the event for the textarea because it doesn't have any items inside it.
It was a "rookie mistake" - I had forgotten to assign the ID to the element. Once I changed the code from this:
boxSection5Total = new TextBox()
{
CssClass = "dplatypus-webform-field-input"
};
this.Controls.Add(boxSection5Total);
...to this:
boxSection5Total = new TextBox()
{
CssClass = "dplatypus-webform-field-input",
ID = "boxSection5Total"
};
this.Controls.Add(boxSection5Total);
...I saw the alert about entering the event.
So the UPDATE shows the faulty code, although it would take someone accustomed to creating the html elements dynamically in C# to catch it.
For "full disclosure," here is the jQuery as it now stands (working as designed):
$(document).on("blur", "[id$=boxSection5Total]", function (e) {
var totalvalue = $(this).val();
var paymenttotalvalue = $('[id$=boxPaymentAmount]').val();
if (totalvalue !== paymenttotalvalue) {
console.log("The value in 'Total' does not equal the previous value in 'Payment Total'");
alert("The value in 'Total' does NOT equal the previous value in 'Payment Total'");
}
else {
console.log("The value in 'Total' DOES equal the previous value in 'Payment Total'");
}
});
This "dawned on me" when I "inspected element" in the F12 tools and saw:
<input name="ctl00$ctl24$g_5f3fedca_19f7_4bc3_b84e_efbef0c48a33$ctl00$ctl153" type="text" class="dplatypus-webform-field-input">
(no ID).

JQuery moving items between SELECT with filtering unexpected behavior

Here is a live demo: jsfiddle
The filtering is working great for the box on the left.
The moving items between the two lists also works great.
The problem occurs when I move an item into the right box, then filter, it removes everything from the right box.
How can I have it leave items in the right box upon filtering and not have those items show up in the left box if they are in the right box (to avoid duplicates)?
//MOVE SPECS BETWEEN BOXES
function moveListItems(sourceID, destinationID) {
var whatToMove = $("#"+sourceID+" option:selected");
if ( sourceID = "excluded-select" ) {
whatToMove.attr('class', 'included-option');
}
if ( sourceID = "included-select" ) {
whatToMove.attr('class', 'excluded-option');
}
whatToMove.remove().appendTo("#"+destinationID);
return false;
}
$("#move-right-btn").click(function(){
moveListItems("excluded-select", "included-select");
return false;
});
$("#move-left-btn").click(function(){
moveListItems("included-select", "excluded-select");
return false;
});
var $opts = $(".excluded-option");
$("#filter-specs-text").keyup(function () {
var searchString = $(this).val().toLowerCase();
$("#excluded-select").empty().append($opts);
$(".excluded-option").each(function () {
var text = $(this).text().toLowerCase();
//found a match - show this entry
if (text.indexOf(searchString) > -1) {
$(this).prop("disabled", false);
}
//no match - hide this entry
else {
$(this).prop("disabled", true).detach();
}
});
});
The problem is the $opts always contains all the .excluded-options, in the onkeyup handler you write, it appends all $opts to the first select and filter the list then, that's why the included options (which should be kept in the second select) are pushed back to the first. To solve this you have to update the $opts each time you move the items between the 2 selects:
$("#filter-specs-text").keyup(function () {
//...
//Use $opts here instead of $('.excluded-option')
$opts.each(function () {
//...
}
}
function moveListItems(sourceID, destinationID) {
var whatToMove = $("#"+sourceID+" option:selected");
//here you update the $opts accordingly...
if(sourceID == "excluded-select") $opts = $opts.not(whatToMove);
else $opts = $opts.add(whatToMove);
whatToMove.remove().appendTo("#"+destinationID);
return false;
}
Note that you should update the $opts instead of re-select the .excluded-option everytime the keyup is triggered, it's so terrible to do it that way.
Demo.
Since you are selecting $opts upfront, those items selected will stay the same even though you change their class or id. You have to reselect them on your keyup event handler.

Events being bound twice or more jquery

I'm trying to generate html on the fly with javascript. I'm binding on the click of buttons on my page. There are multiple buttons on my page which are causing my elements to be bound multiple times which produces the desired results to appear in the amount of times the button has been clicked.
My question is there something that can check if a element is already bound in jquery? If so, how do I incorporate that with the .live() function in jquery.
Here is my code:
$(document).ready(
function () {
$(':button').live("click", ".textbox, :button", function () {
alert("binding");
$(".textbox").click(function () {
defaultVal = this.defaultValue;
if (this.defaultValue) {
this.value = "";
}
});
$(".textbox").blur(function () {
if (this.value == "") {
this.value = defaultVal;
}
});
$('[name="numsets"]').blur(function () {
if (!parseInt(this.value)) {
$(this).val("you need to enter a number");
}
});
$('[name="weightrepbutton"]').click(function () {
var $numsets = $(this).parent().children('[name="numsets"]');
if ($numsets.val() != "you need to enter a number" && $numsets.val() != "Number of Sets") {
var numbersets = parseInt($numsets.val())
repandweight.call(this, numbersets)
$(this).hide();
$numsets.hide();
}
})
});
});
The problem is line 4, every time a button is clicked, all functions that were previous bound seem to be bound to the same function twice, which is a problem.
Thanks for the help!
You are doing it twice ! One inside another. Take out the outer binding and it should work
$(document).ready(function () {
$(document).on("click",".textbox",function () {
defaultVal = this.defaultValue;
if (this.defaultValue) {
this.value = "";
}
});
$(document).on("blur",".textbox",function () {
var item=$(this);
if (item.val() == "") {
item.val(defaultVal);
}
});
$(document).on("blur","input[name='numsets']",function () {
var item=$(this);
if (!parseInt(item.val())) {
item.val("you need to enter a number");
}
});
$(document).on("click","input[name='weightrepbutton']",function () {
var $numsets = $(this).parent().children('[name="numsets"]');
if ($numsets.val() != "you need to enter a number" && $numsets.val() != "Number of Sets") {
var numbersets = parseInt($numsets.val())
repandweight.call(this, numbersets)
$(this).hide();
$numsets.hide();
}
})
});
if you are using jQuery 1.7+ version, consider switching to jQuery on instead of live.
EDIT: Updated live to on as OP mentioned it in the comment.

Compare onclick action of two html button using javascript

I have this two HTML Form buttons with an onclick action associated to each one.
<input type=button name=sel value="Select all" onclick="alert('Error!');">
<input type=button name=desel value="Deselect all" onclick="alert('Error!');">
Unfortunately this action changes from time to time. It can be
onclick="";>
or
onclick="alert('Error!');"
or
onclick="checkAll('stato_nave');"
I'm trying to write some javascript code that verifies what is the function invoked and change it if needed:
var button=document.getElementsByName('sel')[0];
// I don't want to change it when it is empty or calls the 'checkAll' function
if( button.getAttribute("onclick") != "checkAll('stato_nave');" &&
button.getAttribute("onclick") != ""){
//modify button
document.getElementsByName('sel')[0].setAttribute("onclick","set(1)");
document.getElementsByName('desel')[0].setAttribute("onclick","set(0)");
} //set(1) and set(0) being two irrelevant function
Unfortunately none of this work.
Going back some steps I noticed that
alert( document.getElementsByName('sel')[0].onclick);
does not output the onclick content, as I expected, but outputs:
function onclick(event) {
alert("Error!");
}
So i guess that the comparisons fails for this reason, I cannot compare a function with a string.
Does anyone has a guess on how to distinguish which function is associated to the onclick attribute?
This works
http://jsfiddle.net/mplungjan/HzvEh/
var button=document.getElementsByName('desel')[0];
// I don't want to change it when it is empty or calls the 'checkAll' function
var click = button.getAttribute("onclick");
if (click.indexOf('error') ) {
document.getElementsByName('sel')[0].onclick=function() {setIt(1)};
document.getElementsByName('desel')[0].onclick=function() {setIt(0)};
}
function setIt(num) { alert(num)}
But why not move the onclick to a script
window.onload=function() {
var button1 = document.getElementsByName('sel')[0];
var button2 = document.getElementsByName('desel')[0];
if (somereason && someotherreason) {
button1.onclick=function() {
sel(1);
}
button2.onclick=function() {
sel(0);
}
}
else if (somereason) {
button1.onclick=function() {
alert("Error");
}
}
else if (someotherreason) {
button1.onclick=function() {
checkAll('stato_nave')
}
}
}
Try casting the onclick attribute to a string. Then you can at least check the index of checkAll and whether it is empty. After that you can bind those input elements to the new onclick functions easily.
var sel = document.getElementsByName('sel')[0];
var desel = document.getElementsByName('desel')[0];
var onclick = sel.getAttribute("onclick").toString();
if (onclick.indexOf("checkAll") == -1 && onclick != "") {
sel.onclick = function() { set(1) };
desel.onclick = function() { set(0) };
}
function set(number)
{
alert("worked! : " + number);
}
working example: http://jsfiddle.net/fAJ6v/1/
working example when there is a checkAll method: http://jsfiddle.net/fAJ6v/3/

Categories

Resources