jquery each loop only looping once and if using else code stops - javascript

I've got two problems with the following javascript and jquery code.
The jquery each loop only iterates once, it gets the first element with the right ID does what it needs to do and stops.
The second problems is that when I use the else in the code the one inside the each function, it doesn't even tries the next if, it just exits there.
I'm probably doing something fundamental wrong, but from the jquery each function and what I'd expect from an else, I don't see it.
Javascript code:
var $checkVal;
var $checkFailed;
$("#compliance").live("keypress", function (e) {
if (e.which == 10 || e.which == 13) {
var checkID = $(this).parents('td').next().attr('id');
var checkVal = $(this).val();
$('#' + checkID).each(function () {
var cellVal = $(this).text();
if (checkVal == cellVal) {
$(this).removeClass("compFail").addClass("compOk");
} else {
$(this).removeClass("compOk").addClass("compFail");
var checkFailed = True;
}
});
if (checkFailed == 'True') {
(this).addClass("compFail");
} else {
(this).addClass("compOk");
}
}
});
How could I get the each loop to iterate through all instances of each element with the id assigned to the variable checkID, and get the code to continue after the else, so it can do the last if?

An id should appear on a page only once. If you want to have multiple elements with same id, then use a class, not an id.
Your each loop iter only once because you are selecting by id thus you are selecting only one element in the page. If you change you elements to a class it should work like you expect.

This is to illustrate what I'm talking about in my comment, so that you do not remove the wrong var:
var checkVal;
var checkFailed;
$("#compliance").live("keypress", function (e) {
if (e.which == 10 || e.which == 13) {
var checkID = $(this).parents('td').next().attr('id');
//HERE is the first edit
checkVal = $(this).val();
$('#' + checkID).each(function () {
var cellVal = $(this).text();
if (checkVal == cellVal) {
$(this).removeClass("compFail").addClass("compOk");
} else {
$(this).removeClass("compOk").addClass("compFail");
//HERE is the second
checkFailed = True;
}
});
if (checkFailed == 'True') {
(this).addClass("compFail");
} else {
(this).addClass("compOk");
}
}
});
Normally, the way you have it would cause a compile-time error (in a typed language like C#) for redeclaring a variable. Here, it's not clear to me if it will be used as a local variable (ignoring your global variable) or if javascript will combine them and consider them the same. Either way, you should use it as I have shown so that your intent is more clear.
EDIT: I have removed the $ from your variables (var $checkVal) as on jsFiddle it was causing issues. SO if you do not need those $'s, then remove them. Also, note that testing on jsFiddle indicates that you do not need to change your code (other than possibly removing the $ from your declaration) as javascript appears to consider them the same variable, despite the redeclaration, which I find a bit suprising tbh.

The jquery each loop only iterates once, it gets the first element
with the right ID does what it needs to do and stops.
Yes, this is absolutely right for the code you're using:
$('#' + checkID).each(function(){};)
ID attributes are unique. There must be only one element with a given ID in the DOM. Your selector can match only one element. You are iterating over a collection containing just 1 item.

Related

jQuery returns object with length attribute undefined

I was checking if some elements exist with:
if ($(selector).length > 0){
....
}
However, sometimes the returned object (even if the element exists in the DOM and has returned) does not have the length attribute so this never evaluates to true.
This error appears in chrome.
Do you have any idea what the problem might be?
Edit:
I use this code:
var variable;
for(let elem in selectors){
if($(elem).length > 0){
variable = true;
break;
}
else
variable = false;
}
Given a list of selectors, variable is true if at least one of the selectors exists. This is inside a google chrome extension's content script. After this code runs in the plugin I get the same problem even in the console of google chrome.
Edit:
This code does not create a problem:
var variable;
if($(elem).length > 0){
variable = true;
}
else
variable = false;
It seams that the problem is the for loop or/and the break; statement. However, a for loop is needed to make this code work for a list of selectors and not just for one.
It seams that the document.querySelectorAll() does not create the same problem and works as expected. So I used this one instead of the $(). If you only want to check if an element exists it is working just fine.
So this code always returns true if at least one of the selectors exists in the web page:
function exists(selectors){
var selectorExists = false;
for(let i=0; i < selectors.length; i++){
let element = document.querySelectorAll(selectors[i]);
if(element.length > 0){
selectorExists = true;
break;
}
}
return selectorExists;
}
If this is because html is not loaded then we can use timeout
now what i understood from code is you are using for loop for selectors so selectors should come as array not the element within it (elem here) is not array so how elem will have length??
setTimeout(function(){
if ($(selector).length > 0){
for(let elem in selectors){
if($(elem)){
variable = true;
break;
}
else
variable = false;
}
}
},100);

Using .length to check if an element exists in JQuery with concated array

Using the common 'if ID exist' method found here, is it still possible check for the existence of the ID when concating the ID with an array variable like below?
for (var i=0; i < lineData.length; i++)
{
optionData = lineData[i].split(",");
if ($("#" + optionData[0]).length)
{
$("#" + optionData[0]).text(optionData[1]);
}
}
When running this in debugging, if the concated $("#" + optionData[0]) ID doesn't exist it yeilds a result of 'undefined: undefined' and jumps to:
Sizzle.error = function( msg ) {
throw "Syntax error, unrecognized expression: " + msg;
in the JQuery code.
Is it proper code etiquette to use check for, and set, HTML ID's in this manner? Why does this not work in the popular 'exist' method? What can I do to fix it and make it skip ID's that don't exist using this type of ID concatenation with an array string?
http://jsfiddle.net/P824r/ works fine, so the problem is not where you think it is. Simplify your code and add in some checks. You're also not doing anything that requires jQuery, so I don't see how this is a jQuery question, but fine:
function handler(data, i) {
var optionData = data.split(","),
$element;
if (optionData[0] && optionData[1]) {
$element = $("#" + optionData[0]);
if ($element.length > 0) {
// omitting >0 as 'trick' causes JS coercion from number to boolean.
// there's literally no reason to ever do so: it's both slower and
// hides your intention to others reading your code
$element.text(optionData[1]);
}
} else { console.error("unexpected optionData:", optionData);
}
lineData.forEach(handler);
but we can do this without jQuery, since we're not really using for anything that we can't already do with plain JS, in the same number of calls:
function handler(data) {
var optionData = data.split(",");
if (optionData.length === 2) {
var id = optionData[0],
content = optionData[1],
element = document.getElementById(id);
// because remember: ids are unique, we either get 0
// or 1 result. always. jQuery makes no sense here.
if (element) {
element.textContent = content;
}
} else { console.error("unexpected input:", optionData);
}
lineData.forEach(handler);
(the non-jquery version unpacks the optionsData into separate variables for improved legibility, but the ultimate legibility would be to make sure lineData doesn't contain strings, but just contains correctly keyed objects to begin with, so we can do a forEach(function(data) { ... use data.id and data.content straight up ... }))
If you want to keep this jQuery-related, there's more "syntax sugar" you're not making use of:
// check for ID in array
jQuery.each(someArray,
function(index, value) {
var the_id = $(value).attr('id');
if ( the_id !== undefined && the_id !== false ) {
// This item has an id
}
});

Trying to make div background change color when 2 ids are true

I am trying to make each div's background change color when 2 ids exist. it is not changing the color. I cannot figure out what I am doing wrong. I am brand new to javascript. I have an embedded stylesheet and dont know if the javascript will override the css.
Also, I know some PHP and want to 'echo' the variables throughout the program so that I can see what the string value is in order to debug my own code. what is the easiest way to do this?
function drop(ev){
ev.preventDefault();
var image = ev.dataTransfer.getData("content");
ev.target.appendChild(document.getElementById(image));
var mydiv = '';
for (var i=0;i<9;i++)
{
if ($('#target'.i).find('#answer'.i).length == 1)
{
mydiv = document.getElementById('target'+i);
mydiv.style.backgroundColor = '#00CC00';
}
else
{
mydiv = document.getElementById('target'+i);
mydiv.style.backgroundColor = '#FF0000';
}
}
}
I think your problem may be on this line you have . not + to build the id's correctly.
if ($('#target'.i).find('#answer'.i).length == 1)
so your code should be:
if ($('#target'+i).find('#answer'+i).length == 1)
Keeping in mind I'm no jQuery wizard, my first notion was something like this:
$('div[id^=target]').each(function() {
var el = $(this).find('div[id^=answer]').addBack();
el.css('backgroundColor', el.length > 1 ? '#00CC00' : '#FF0000');
});
...but then I noticed that unlike your example, I was changing both the parent and child div. Something like this might be closer to your intent:
$('div[id^=target]').css('backgroundColor', function () {
return $(this).find('div[id^=answer]').length ? '#00CC00' : '#FF0000';
});
You also could retain the for loop if that's your preference:
for (var i = 0; i < 9; ++i) {
$('div#target' + i).css('backgroundColor', function() {
return $(this).find('div#answer' + i).length ? '#00CC00' : '#FF0000';
});
}
...and, just for fun, something kinda esoteric:
$('div[id^=target]:has(div[id^=answer])').css('backgroundColor', '#00CC00');
$('div[id^=target]:not(:has(div[id^=answer]))').css('backgroundColor', '#FF0000');
Fiddle!
Your code should work (see fiddle) with the correct operator for concatenation, i.e. with + instead of ., however here are a few points you should bear in mind :
Point 1 :
Among all the i variables you're iterating over in your for loop, if there is no div with id equal to "target" + i you will end up in the following else block :
else
{
mydiv = document.getElementById('target'+i); // null
mydiv.style.backgroundColor = '#FF0000';
}
At that place mydiv will be null and mydiv.style will throw an error.
Point 2 :
It seems you used jQuery to find the answers elements, while you used document.getElementById, which is part of the DOM API, to select then the target element. It would have been more consistent to use jQuery there too.
Point 3 :
If you want to simply output the value of some variable you can use console.log, which will output in the javascript console of the browser. The console object is provided by the browser, therefore you may not have the console.log method, but if you are using an up to date browser there is a good chance you will have it.
To summarize, see this fiddle for an example that takes these points into account.

how to check if a checkbox exists

The check box's exist for each row. the table is created by PHP and I need a way to check if the check box exists. when they are created they are given the ID of checkbox_(an incrementing number).
This is what I have so far, but it does not work on checking if the element exists.
var check = true;
var todelete = "";
var counter = 0;
//check if box exisits and record id and post
while(check)
{
if ($("#Checkbox_"+counter).length > 0)
{
todelete = todelete + $("#Checkbox_"+counter).value;
counter = counter + 1;
}
else
{
check = false;
}
}
I have also tried
if ($("Checkbox_"+counter))
if (document.getElementById("tbody").value == null)
Update:
Even with the # symbol or if i do it by javascripts element ID - when I debug the DOM, it hits the while, then the if, adds the value to todelete, adds 1 to the counter, then it goes back to the while, then hits the if
Then bounces back up to the while without even going into the if or the else???
this I do not understand, then it just bounces up and down between the two lines and crash's the browser?
Update2:
I needed to .tostring() the counter when adding it to the string for an element id. problem solved
You can use
if ($("#Checkbox_"+counter).length > 0)
I'm assuming that 'Checkbox_0' is an ID, so I've added the # symbol. If it's the name of the checkbox, you can use
if ($("input[name='Checkbox_"+counter+"']").length > 0);
[edit]Also, you should check to make sure you do / don't need the capital 'C'.
You can use for "checkbox exists in this case"
if ($("#Checkbox_"+counter).length > 0) {
//checkbox exists
}
if (($("#Checkbox_"+counter).length) > 0) {
...
//Or something more generalized
jQuery.fn.exists = function(){
return jQuery(this).length>0;
}
//then, if you have valid selector
if ($("#Checkbox_"+counter).exists()){
//do something here if our selected element exists
}
// if document.getElementById(name) do not exist
// document.getElementById(name).value generate already an error
if (document.getElementById(name) != null) {
// you code if checkbox exist
}

nextSibling issue, should be simple

Ok, I'm trying to come to grips with this nextSibling function in JS. Here's my issue within the following code...
var fromRow = document.getElementById("row_1");
while(fromRow.nodeType == 1 && fromRow.nextSibling != null)
{
var fRowId = fromRow.id;
if (!fRowId) continue;
// THIS ONLY gets done once and alerts "row_1" ONLY :(
alert(fRowId);
fromRow = fromRow.nextSibling;
}
Ok can someone please tell me what is wrong with this code? There are siblings next to this document.getElementById("row_1"); element for sure as I can see them, and they all have id attributes, so why is it not getting the id attributes of the siblings?? I don't get it.
row_1 is a TR element, and I need to get the TR elements next to it within this table, but for some reason, it only gets the 1 element that I can already get using document.getElementById, arggg.
Thanks guys :)
Try:
var fromRow = document.getElementById("row_1");
while(fromRow !== null)
{
var fRowId = fromRow.id;
if (!fRowId || fromRow.nodeType != 1) {
fromRow = fromRow.nextSibling;
continue;
}
// THIS ONLY gets done once and alerts "row_1" ONLY :(
alert(fRowId);
fromRow = fromRow.nextSibling;
}
While fromRow.nextSibling != null would halt on the second to last iteration because you already set fromRow to its nextSibling at the end. Also, you don't necessarily want to halt if the next node isn't an element, you just want to move onto the next one if possible. Finally, if you hit the continue in your original example, you'll run into an endless loop because fromRow would never change value.
Your while loop stops as soon as it encounters a node not of type 1. So if there is any whitespace between your elements the while loop will break after the first element.
What you probably want is:
while(fromRow.nextSibling != null)
{
if(fromRow.nodeType == 1) {
...
}
}

Categories