What's wrong with my logic? (JS string Length) - javascript

A couple days ago, on a site that I'm the only author on, I added this code to a script:
if (PowerArray[0][0].length < 1);
{
return false;
}
and everything worked fine. When PowerArray[0][0] was "70", the script ran. When PowerArray was empty, the script didn't run past the above quoted line.
This is no longer true. For the life of me, I can't figure it out. I tested with variants of the code, like below:
if (PowerArray[0][0].length < 1);
{
alert(PowerArray[0][0].length);
return false;
}
and set PowerArray[0][0] = "70". When I run the code, I get an alert with "2" in the text. This is the only place that I have an alert in the script. What's going on here, and how do I fix it?
Note: The expected behavior is, of course, no alert, because "70" has a length of 2, and shouldn't trigger the truth of the if.
Edit: 1) Yes, the False in the first block was a typo. It's been corrected. 2) The expected behavior was for it to stop processing if (and only if) PowerArray[0][0].length was 0. 3) I had previously initialized PowerArray as an empty array, and then copied an array (which had the potential to be empty) into it.

You should remove semicolon from if statement, it terminates your statement there.
And yes, when your PowerArray is empty,
PowerArray[0][0] will throw an undefined error,
So should put a null check for that as well.

when PowerArray is empty PowerArray[0] gives undefined then you will get an error for PowerArray[0][0] saying TypeError: Cannot read property '0' of undefined that is why the script is nor running after that line
if (PowerArray && PowerArray[0] && PowerArray[0][0] && PowerArray[0][0].length < 1)
{
return false;
}

I think the semicolon after the if is the issue.
I would also check if PowerArray is a valid 2D array implementation.
Check this link for ideas How can I create a two dimensional array in JavaScript?
Start by changing it to this if (PowerArray[0][0].length < 1)

try this
if (PowerArray[0]) {
if (PowerArray[0][0].length < 1) {
return False;
}
}

Related

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!

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.

javascript variables always not equal

I have two variables, totalGuess and condensedAnswer. I am creating a jQuery click event and if totalGuess doesn't equal condensedAnswer then the click event will not occur and a div called message will display the message "Sorry, but your answer is incorrect. Please try again."
The problem is, totalGuess in the if statement is never equal to condensedAnswer. I've tried seeing typeof and they are both strings. I've tried console.log(totalGuess+"\n"+condensedAnswer); and they both return the same value. I've tried hardcoding the condensedAnswer, and totalGuess was able to be equal to the hardcoded answer. But when I tried comparing condensedAnswer with the hardcoded answer, it's not equal, even though the console.log value for condensedAnswer is the same. I'm not what's wrong.
Here's the code snippet:
$('.submitGuess').click(function(e){
var totalGuess = "";
var condensedAnswer = answer.replace(new RegExp(" ","g"), "");
$('.crypto-input').each(function(){
totalGuess += $(this).val();
});
// if incorrect guess
if(totalGuess !== condensedAnswer) {
$('.message').text("Sorry, but your answer is incorrect. Please try again.");
e.preventDefault();
}
// if user wins, congratulate them and submit the form
else {
return true;
}
});
If it helps, here's the page, just a random test cryptogram plugin for Wordpress:
http://playfuldevotions.com/archives/140
The problem has nothing to do with the check. The problem is the fact your value you are checking against has hidden characters. However you are getting that string has the issue.
Simple debugging shows the problem
> escape(totalGuess)
"God%27sMasterpieceMatthew15%3A99Psalms129%3A158"
> escape(condensedAnswer)
"God%27sMasterpieceMatthew15%3A99Psalms129%3A158%00"
It has a null character at the end.
Now looking at how you fill in the answer you have an array with numbers
"071,111,100,039,...49,053,056,"
Look at the end we have a trailing comma
when you do a split that means the last index of your array is going to be "" and hence why you get a null.
Remove the trailing comma and it will magically work.

cant compare 0 in a conditional statement in js

well this is in node to be exact but, when i do the following conditional statement on a string of a length of zero or above zero, it will only ever do the condition if the string is not 0.
if(string.length == 0)
{
console.log(string.length)
} else {
console.log(string.length)
};
no matter what it wont respond if the string.length is 0. i have also tried:
if(string.length > 0)
{
console.log('greater than zero')
} else {
console.log('zero')
};
but with the same results. no matter what it wont respond if the string.length is zero. i have printed the string.length outside of the if/else statement, and have been able to have it print 0. why wont the conditional statement work in this case? why does it just not respond if the string.length == 0?
Seems to work. Fiddle here Firebug records a 0 if there is nothing in the <div>
i was getting whitespace if the string was 0. i solved the error by doing string.trim()

If statement condition is met, but contents not executed?

I've got an two if() statements, for which the conditions are both met with the default values in the <select> and <input> form fields I've tested this by assigning the values to a variable and writing the variable. (0 and Url).
However, it seems that neither if() statement's contents execute properly.
Here's a link to my JSFiddle: http://jsfiddle.net/cfRAk/2/
Any edits/answers as to why this is happening would be greatly appreciated!
Change this line:
var geo_select_val = $('select[name=g_country\\[1\\]]').val();
To this:
var geo_select_val = parseInt($('select[name=g_country\\[1\\]]').val());
The thing is geo_select_val is actually "0" and not 0. Converting a string to boolean will only result in false if string is empty. "0" is not empty, so it was being evaluated as true. Since you are going !geo_select_val, it never goes in.
Caveat: this fix will only work if you make sure all values are numbers. If that's not the case, check for equality with "0"
Here's the code you're asking about:
$('#post-form').click( function() {
var geo_select_val = $('select[name=g_country\\[1\\]]').val();
if(!geo_select_val) {
var geo_url_val = $('input[name=g_url\\[1\\]]').val();
if(geo_url_val != "http://google.com") {
$('#notification').html("You need to enter a valid url");
}
}
});
When I set a breakpoint in this click function and then click on the Post Form div, geo_select_val comes back as "0" which means that if(!geo_select_val) will fail because geo_select_val does have a value so the first if condition will never be executed.
Perhaps you want the first if condition to be:
if (geo_select_val != "0") {
which will tell you if some other value besides the default has been selected (assuming you add other options to that select tag with different values).

Categories