Can't run two for loop statement within same if statement? - javascript

I have the following JS code, I feel weird that only the first for loop can run, but the 2nd part doesn't work. I even tried to make two different if statement and include the for loop separately, but the same thing happened. If I run the for loop separately (by deleting another for loop), both of them can run, means both of the logic should be correct. Please help.
var s = "<?php printf($resultDataOrderInfo[0][status]); ?>";
if(s == "Processing"){
var t = document.getElementsByTagName("input");
for (i=0; i<=t.length; i++){
t[i].setAttribute("readonly","true");
} // only this above part can run
var d = document.getElementsByName("delete");
for (i=0; i<=d.length; i++){
d[i].setAttribute("hidden","true");
}
}

I think you want to change all of the <= to <. If length is equal to 0, then it is going to execute once, but fail due to the length being zero. Which, I believe is the issue of it not reaching the second for loop, due to an error occurring on the first.

Related

Why does this code create an infinite loop?

I have a JavaScript problem. I have a function that runs when I hit a button, the variables are changed via JavaScript. Everything in the function runs properly but this one last part:
else if (upgrade == "upgMiner4") {
var cost="500";
var qty="1";
var readCash=parseInt(document.getElementById("cash").innerHTML);
while (readCash >= cost) {
document.getElementById("cash").innerHTML += "-"+cost;
document.getElementById("cash").innerHTML = eval(document.getElementById("cash").innerHTML);
document.getElementById("gpt").innerHTML += "+"+qty;
document.getElementById("gpt").innerHTML = eval(document.getElementById("gpt").innerHTML);
}
}
When I run this code, it freezes and creates an infinite loop. I don't see the problem here, so I would like to know if you guys could help me, thanks!
-Zachucks
Your code inside the while loop does nothing to update readCash or cost, so if the condition (readCash >= cost) is true, this will never change, and the while loop will never exit.
I should add that a reader cannot tell what the evals are evaluating--so it's hard to be sure what is going on. However, notice you assign to readCash and cost exactly one time and that you never do this again. So why would it change?
Because you set readCash value only once and don't update it together with innerHTML with your div. That's why your loop doesn't end.
Working code:
while (readCash >= cost) {
document.getElementById("cash").innerHTML += "-"+cost;
document.getElementById("cash").innerHTML = eval(document.getElementById("cash").innerHTML);
document.getElementById("gpt").innerHTML += "+"+qty;
document.getElementById("gpt").innerHTML = eval(document.getElementById("gpt").innerHTML);
readCash = document.getElementById("cash").innerHTML;
}
neither readCash or cost variable are changing in the last while loop. That's why you're facing a loop. Probably you have to increment/decrement readCash or cost vars with a logic you're missing. Or maybe you don't actually need a while statement, but simply an if

if statements in for loop both executing instead of just one

First If statement works just fine, then it goes into the for loop as expected BUT THEN OUT OF NOWHERE, it decides to execute both if statements (which they are contradictory of each other "==" and "!=")..I don't understand :(
if($scope.firstinitial==$scope.firstinput&&$scope.secondinitial==$scope.secondinput){
$scope.initialmatches="MATCHES THE INITIALS";
for (var i=0; i<$scope.discountcodes.length; i++) {
console.log($scope.discountcodes[i]);
if($rootScope.discountcodeinput.attempt.toLowerCase()!=$scope.discountcodes[i]){
$scope.changeBack();//DOES ONLY IF INPUT DOES NOT MATCH DATA
}
if($rootScope.discountcodeinput.attempt.toLowerCase()==$scope.discountcodes[i]){
console.log($scope.discountcodes[i]);//DOES ONLY IF INPUT MATCHES DATA
$scope.changeBackAgain();
}
}
}
UPDATE:
After bug testing, only the last discount code when matched works correctly...which boggles my mind even further. So when the user types in the discount code which matches the last discount code in the array, then only the first if statement triggers and not the second one. Any ideas?
I think whatever is happening inside $scope.changeBack(); is making the second condition true
If $scope.changeBack(); does something to modify discountcodes[i] or $rootScope.discountcodeinput.attempt it is possible for the second if statement to execute. What you probably mean to do is:
for (var i=0; i<$scope.discountcodes.length; i++) {
if($rootScope.discountcodeinput.attempt.toLowerCase()!=$scope.discountcodes[i]){
$scope.changeBack();//DOES ONLY IF INPUT DOES NOT MATCH DATA
}
else {
$scope.changeBackAgain();
}
}
Apparently using the == operator can have very unexpected results due to the type-coercion internally, so using === is always the recommended
also add an else statement in there if you don't need both of them executing.
Other than that I would say that something is changing, I would step through it in the debug window and see what the current results are for each variable or print them to the console.
if($scope.firstinitial==$scope.firstinput&&$scope.secondinitial==$scope.secondinput){
$scope.initialmatches="MATCHES THE INITIALS";
for (var i=0; i<$scope.discountcodes.length; i++) {
console.log($scope.discountcodes[i]);
if($rootScope.discountcodeinput.attempt.toLowerCase()!==$scope.discountcodes[i]){
$scope.changeBack();//DOES ONLY IF INPUT DOES NOT MATCH DATA
}
else if($rootScope.discountcodeinput.attempt.toLowerCase()===$scope.discountcodes[i]){
console.log($scope.discountcodes[i]);//DOES ONLY IF INPUT MATCHES DATA
$scope.changeBackAgain();
}
}
}
Trying using the else if statement to run one code then the other
<script>
if($scope.firstinitial==$scope.firstinput&&$scope.secondinitial==$scope.secondinput){
$scope.initialmatches="MATCHES THE INITIALS";
for (var i=0; i<$scope.discountcodes.length; i++) {
console.log($scope.discountcodes[i]);
if($rootScope.discountcodeinput.attempt.toLowerCase()==$scope.discountcodes[i]){
console.log($scope.discountcodes[i]);//DOES ONLY IF INPUT MATCHES DATA
$scope.changeBackAgain();
} else if($rootScope.discountcodeinput.attempt.toLowerCase()!=$scope.discountcodes[i]){
$scope.changeBack();
}
}
}
</script>
Obviously ($rootScope.discountcodeinput.attempt.toLowerCase()!=$scope.discountcodes[i] and ($rootScope.discountcodeinput.attempt.toLowerCase()==$scope.discountcodes[i] can not be true at the same time. So I guess you are doing some magic inside $scope.changeBack() that changes the value of either $rootScope.discountcodeinput.attempt or $scope.discountcodes[i], so when the second if gets checked, the value has already changed and the condition passes.
I would suggest breaking out of the iteration as soon as you know you are done, by adding a continue statement. Something like this:
for (var i = 0; i < $scope.discountcodes.length; i++) {
console.log($scope.discountcodes[i]);
if ($rootScope.discountcodeinput.attempt.toLowerCase() != $scope.discountcodes[i]) {
$scope.changeBack(); //DOES ONLY IF INPUT DOES NOT MATCH DATA
continue; // done
}
// no need to check again
console.log($scope.discountcodes[i]); //DOES ONLY IF INPUT MATCHES DATA
$scope.changeBackAgain();
}
I figured it out...
Essentially the for loop was going through and checking both if statements with each object, if the first object matched it would trigger the first if statement and not the second. BUT then the for loop would continue and look at the next object in the array and only trigger the second if statement...then it would loop through with the third object in the array and again only trigger the second if statement...so on and so on.
The workaround I came up with was just embedding both into another if statement that checked for a var value of yes
if($scope.value=="no")
then I placed the not equal if statement (!=) first and the equal if statement (==) second. Finally, I added in the (==) if statement:
$scope.value="yes";
thus avoiding going through the parent if statement on every loop of the for loop.
Thanks everyone for the help...this was killing me!

javascript - if statement excecutes both if and else blocks

This is my code:
var counter = 0;
function showAddButton() {
var cnt = document.getElementsByClassName('img-cntnr').length;
counter++; // for detecting double excecution in debugger
if (cnt < 4) {
$('#div-add').show();
} else {
$('#div-add').hide();
}
}
//someweher in my code
showAddButton();
when I call function in my code, JavaScript executes both $('#div-add').show(); and $('#div-add').hide(); lines.
I've defined a variable (counter) and watched that in debugger for detecting parallel twice call. but there is not any parallel execution and in first call if-statement executes both blocks!
how can I fix that?
Thank You.
Your issue is most likely your if statement is not the logic you want perhaps your < should be a >, because even if you were hitting it multiple times that shouldn't really effect the results of the problem because the only way for the else to hit would be if you count was actually greater than what you expected.
So either something else is hiding the div, something is modifying the class count, or your logic is not what you expected it to be.
However you can try this line of code which will get rid of all the excess logic you have
$('#div-add').toggle($('.img-cntnr').length < 4)
you can use a boolean in the toggle fuction to set the display
you can see the toggle documentation here
Here look at this jsFiddle
I cannot see any duplicate calls, nor that both blocks of if/else are executed in one call.
showAddButton always shows element because it depends on:
document.getElementsByClassName('img-cntnr').length;
which gets length of how many elements matched img-cntnr class. So, unless you are adding elements with that class to the DOM, that count will always be the same.
If you can show us jsFiddle that prints both show and hide we will have something to go by.
There is definitely something else that is causing the code to run again. What I would do is add a killer to your js and modify the else statement to look like this:
var counter = 0;
var killer = false;
function showAddButton() {
var cnt = document.getElementsByClassName('img-cntnr').length;
counter++; // for detecting double excecution in debugger
if (cnt < 4) {
$('#div-add').show();
killer = true
} else if(killer === false) {
$('#div-add').hide();
}
}
//someweher in my code
showAddButton();

Can't assign querySelectorAll() to a variable - weird behaviour

I was trying to crawl a very old website for a specific tag, I need to get it by it's for= attribute. So I used this piece of code.
var character = document.querySelectorAll("label[for=char_1]");
For some reason it returns an undefined, but I was using this script for a few days now and it worked like a charm. Here's the fun part. Typing that command in browsers console will result in undefined. But typing this alone:
document.querySelectorAll("label[for=char_1]");
Will return a proper NodeList. Why it won't assign to a variable...?
edit: It seems that deleting var and typing character without it will make it work. It's resolved but I would still love to get an answer to "why is this happening"?
edit2:
for (var i = 0; i < 15; i++) {
var character = document.querySelectorAll("label[for=char_" + i +"]");
console.log(character); // this will return [] from the script.
var color = character[0].children[0].style.color;
}
A simple for loop. All I get is Cannot read property 'children' of undefined. But I can type in the very same command document.querySelectorAll... and it will work in the browser and will return NodeList.
I had it working like this in a very hacky script. It worked.
var character1 = document.querySelectorAll("label[for=char_1]");
var characterColor1 = character1[0].children[0].style.color;
edit3:
var character1 = document.querySelectorAll("label[for=char_1]");
var characterColor1 = character1[0].children[0].style.color;
var character2 = document.querySelectorAll("label[for=char_2]");
var characterColor2 = character2[0].children[0].style.color;
// ...
The above code works without a single problem though. I don't think it's DOM not being ready as this code is also run from Greasemonkey script and it works. The only difference is the for loop.
var x = ""; // returns undefined, because it's a var assignment.
var elements = document.querySelectorAll('div');
That's expected behavior when pasted into the console.
edit: It seems that deleting var and typing character without it will make it work. It's resolved
I'm afraid you're creating a global scope variable now. or perhaps characters is an already defined variable in that scope.
Buhah, as I said in edit 3 "the only difference is the for loop". I was so busy trying to find an answer in the DOM-related things that I made the simplest mistake ever done in programming.
See?
char_1
With...
for(var i = 0...)
0! And I was testing char_1 in the browser instead of char_0. Which - truly - returns [] instead of something useful. Time to go on a holiday break I guess, my brain seems to be there already. :)

Unchecking and simulating a click on checkboxes in Javascript

I am admittedly a super newbie to programming in general. I am trying to design a quick piece of javascript to inject on a website for a class that will both uncheck and simulate a click on a series of checkboxes. This is nothing malicious, the web form we use to download data for use in this class presents way more variables than necessary, and it would be a lot more convenient if we could 'uncheck' all and only check the ones we want. However, simply unchecking the boxes via javascript injection doesn't yield the desired result. A mouse click must be simulated on each box. I have been trying to use the .click() function to no avail. Any help is greatly appreciated. My code below fails with an error of:
"TypeError: Cannot read property 'click' of null"
CODE:
var getInputs = document.getElementsByTagName("input");
for (var i = 0, max = getInputs.length; i < max; i++){
if (getInputs[i].type === 'checkbox')
getInputs[i].checked = false;
document.getElementById('shr_SUBJECT=VC' + i).click();
}
--------EDIT#1--------------
FYI, this is the website that I am trying to use this on:
http://factfinder2.census.gov/faces/nav/jsf/pages/searchresults.xhtml
if you search for and open up any of these tables they are huge. It would be awesome if I could easily pare down the variables by 'unchecking' and 'clicking' them all at once via javascript.
The code at the bottom ALMOST works.
The problem I am running into now is that it throws an error after the first or second run through the for loop:
"TypeError: document.getElementById(...) is null"
I understand that this is because the value it's trying to find doesn't exist? Sometimes on these tables the checkboxes are greyed out/don't exist or are otherwise 'unclickable'. My theory as to why I am getting this error is because in the table/form the 'available' ID's will start around:
shr_SUBJECT=VC03 or sh_SUBJECT=VC04
and it may then skip to:
shr_SUBJECT=VC06 then skip to shr_SUBJECT=VC09 and so on...
So if the for loop hits an ID that isn't available such as 05 or 07, it returns a null error :(
I did some reading and learned that javascript is able to 'catch' errors that are 'thrown' at it? My question now is that I'm wondering if there is an easy way to simply iterate to the next ID in line if this error is thrown.
Again, any and all help is appreciated, you guys are awesome.
OLD DRAFT OF SCRIPT
var getInputs = document.getElementsByTagName("input");
for (var i = 3, max = getInputs.length; i < max; i++){
if (getInputs[i].type === 'checkbox' && i < 10){
var count = i;
var endid = count.toString();
var begid = "shr_SUBJECT=VC0";
var fullid = begid.concat(endid);
document.getElementById(fullid).click();
}
else if(getInputs[i].type === 'checkbox' && i >= 10){
var count = i ;
var endid = count.toString();
var begid = "shr_SUBJECT=VC";
var fullid = begid.concat(endid);
document.getElementById(fullid).click();
}
}
--------EDIT#2----------
An example of a table that I am trying to manipulate can be found at this URL:
http://factfinder2.census.gov/faces/tableservices/jsf/pages/productview.xhtml?pid=ACS_12_5YR_DP02&prodType=table#
If you click on the 'Modify Table' button, you are able to select/deselect specific variables via the checkboxes. If you right-click on a couple of 'active' checkboxes and inspect the elements, and it looks something like this:
<input id="shr_SUBJECT=VC03" checked="" alt="hide SUBJECT=VC03" name="" value="" onclick="javascript:hiderow('SUBJECT=VC03');" type="checkbox">
<input id="shr_SUBJECT=VC25" checked="" alt="hide SUBJECT=VC25" name="" value="" onclick="javascript:hiderow('SUBJECT=VC25');" type="checkbox">
Thank you so much #Jonathan Steinbeck for the tip about the ternary operator, it really cleaned up my code.
The script works properly, but the problem I am running into now is that it doesn't iterate enough times after the try, catch statement. If there is a gap in the id #'s; say it jumps from shr_SUBJECT=VC19 to shr_SUBJECT=VC=24 the script will stop running. Is there a way to make it keep retrying the try/catch until it gets a valid ID # or one that exists/is an active checkbox?
CURRENT DRAFT OF SCRIPT :
var getInputs = document.getElementsByTagName("input");
for (var i = 3, max = getInputs.length; i < max; i += 1) {
try {
if (getInputs[i].type === 'checkbox'){
document.getElementById("shr_SUBJECT=VC" + (i < 10 ? "0" : "") + i).click();
}
}
catch (err) {
i+=1;
if (getInputs[i].type === 'checkbox'){
if (getInputs[i].type === 'checkbox'){
document.getElementById("shr_SUBJECT=VC" + (i < 10 ? "0" : "") + i).click();
}
}
}
}
When you call document.getElementById() with a non-existing ID, null is returned. Therefore this error means that you're trying to call the .click() method on null, which can't work.
So you should check what the correct ID naming scheme for the elements you want is. Maybe the elements' count starts with 1 instead of 0?
Also, the .click() doesn't work for all elements like you would expect as far as I know. So depending on the kind of element you are trying to retrieve you might have to create and dispatch your own event as suggested by RobG's comment.
EDIT in response to your recent edit:
You can wrap code that throws errors in a try-catch like this:
for (var i = 3, max = getInputs.length; i < max; i += 1) {
try {
document.getElementById("the_ID").click();
}
catch (error) {
console.error(error);
// continue stops the current execution of the loop body and continues
// with the next iteration step
continue;
}
// any code here will only be executed if there's not been an error thrown
// in the try block because of the continue in the catch block
}
Also, what are you doing with the 'i' variable? It doesn't make sense to assign it to so many variables. This does the same:
document.getElementById("shr_SUBJECT=VC" + (i < 10 ? "0" : "") + i).click();
The ... ? ... : ... is an operator (called the 'ternary operator') that works like this: evaluate the expression before the "?" - if it results in a truthy value, the expression between "?" and ":" is evaluated and becomes the result of using the operator; if the condition results to false, the part after the ":" is evaluated as the value of the operator instead. So while "if" is a statement in JavaScript (and statements usually don't result in a value), the ternary operator can be used as an expression because it results in a value.
By concatenating a string with something else, you are forcing the 'something else' to be converted to string. So an expression like this will usually result in a string:
"" + someNonStringVar
Also, it doesn't make sense to define variables in a loop body in JavaScript. JavaScript variables have function scope, not block scope. What this means is that any variables defined in the loop body exist inside the whole function as well. Therefore it is recommended to write all of the "var"s at the top of your function to make it clear what their scope is. This behaviour of JavaScript is called 'hoisting', by the way.
I've furthermore taken a look at the URL you've given in your recent edit but I fail to find the kind of naming scheme for IDs you describe. In which table did you find those?
Edit in response to your second edit:
You shouldn't mess with the 'i' variable inside the body of a for loop. It makes your code much harder to reason about and is probably not what you want to do anyway. You don't need to handle the next step of the iteration in the catch block. The 'i' variable is incremented even if there's an error during fetching the element from the DOM. That's why you use catch in the first place.

Categories