Javascript behaving weirdly - javascript

the following function does not work as I thought it should have. For some reason, the loop breaks whenever one the the validate function returns false. Why is that?
Here is my code :
function validateGroup(input) {
if (!input.value.match(/^[0-9]{0,2}$/)) {
$(input).addClass("invalidField");
return false;
}
$(input).removeClass("invalidField");
return true;
}
function validateClass(input) {
if (!input.value.match(/^[a-zA-Z0-9-]{0,9}$/)) {
$(input).addClass("invalidField");
return false;
}
$(input).removeClass("invalidField");
return true;
}
function validateData() {
var rows = document.getElementsByTagName("tbody")[0].getElementsByTagName("tr");
var valid = true;
for (var i = 0, arrayLength = rows.length; i < arrayLength; ++i) {
valid = valid && validateClass(rows[i].getElementsByTagName("input")[0]);
valid = valid && validateGroup(rows[i].getElementsByTagName("input")[1]);
valid = valid && validateGroup(rows[i].getElementsByTagName("input")[2]);
}
return valid;
}
Thanks a lot!

the statement valid && validateClass(...) will not call the validateClass method if valid is false. I think what you want to do is change the order of those to
valid = validateClass(rows[i].getElementsByTagName("input")[0]) && valid;
valid = validateGroup(rows[i].getElementsByTagName("input")[1]) && valid;
valid = validateGroup(rows[i].getElementsByTagName("input")[2]) && valid;
Javascript doesn't bother evaluating the rest of an && expression if it already knows that the result is false.

It looks like you want to run the validate functions on each iteration even if ‘valid’ was already set to false. However the && operation you are using will short-circuit, so although the loop will continue the validate functions will not be called on subsequent iterations.
A really simple alternative which would work the way you want would be:
for (var i = 0, arrayLength = rows.length; i < arrayLength; ++i) {
if(!validateClass(rows[i].getElementsByTagName("input")[0])) valid = false;
if(!validateGroup(rows[i].getElementsByTagName("input")[1])) valid = false;
if(!vvalidateGroup(rows[i].getElementsByTagName("input")[2])) valid = false;
}

It sounds like that is the intent of the function. The three lines of
valid = valid && validate...
mean that if any of the validate functions ever hits false valid will remain false for the rest of the loop.

I think it's because of the lazy evaluation scheme Javascript uses with &&. Try a single & instead.
Short-circuit evaluation: Support in common programming languages

It's called short-circuiting. Quick fix: replace each line with
valid = validateClass(rows[i].getElementsByTagName("input")[0]) && valid;

Related

Angular 2 - if condition getting true for all values

I have been stuck at a point, my if condition is returning true for all conditions, I am checking that a value is greater or not.
Code:
hideAmountModal() {
var self = this;
self.home_delivery_charge = self.storeService.fetchHomedeliveryData(self.shopId);
self.home_delivery_charge.subscribe((res: any) => {
for (var i = 0; i < res.length; i++) {
if (self.deliveryData.delivery_charge > res[i].amount) {
self.check_delivery_charge = true;
console.log('Deliverycharge',self.deliveryData.delivery_charge,'result',res[i].amount);
console.log('deliver charge is greater',self.check_delivery_charge);
}
else if (self.deliveryData.delivery_charge < res[i].amount){
self.check_delivery_charge = false;
}
}
})
self.DeliveryChargeValue = true
self.selectAmountModal.hide();
}
From the console what I get is below:
Where have I gone wrong?
Try converting both values to number type
if (parseInt(self.deliveryData.delivery_charge) > parseInt(res[i].amount)) {
}
Change your if condition from:
if (self.deliveryData.delivery_charge > res[i].amount)
To this:
if (Number(self.deliveryData.delivery_charge) > Number(res[i].amount))
Doing this, you would be explicitly type-casting your input type into number.
Remember: You'll get NaN (Not-a-Number) if your input can't be converted to number type.
In case you don't want this behavior you could always use parseInt which uses Javascript's Number() function under-the-hood as shown here.
Be careful because you are not handling the equal case, which you should include on the else if. Can you check that the values that you are comparing are numbers? This is probably the problem.
You console.log only value when is true
Try add console.log here :
else if(self.deliveryData.delivery_charge < res[i].amount) {
self.check_delivery_charge = false;
}

charAt not evaluating

I am trying to write a function that will evaluate equality of characters in a string and return true if 3 in a row match. The charAt() doesn't seem to be working as the if statement always goes to the else block.
function myFunction(num1)
{
var checkNum1;
for (var i = 0; i < num1.length; i++)
{
if (num1.charAt(i) == num1.charAt(i+1) && num1.charAt(i) == num1.charAt(i+2))
{
checkNum1 = true;
break;
}
}
if (checkNum1 == true)
{
return true;
}
else
{
return false;
}
}
What should I be doing to get the last "if" block to return true?
The code that you have provided works fine with strings ie: myFunction("257986555213") returns true.
However, myFunction(257986555213) returns false as expected as charAt is a String method.
As a fail-safe approach, you can try adding the following line to your method at the beginning:
num1 += '';
This should convert your argument to string and you should get your results..
Hope it Helps!!

what is the order of boolean logic in Javascript?

I wanted to use two Not and one and in booleans to test if the variable is neither upper case nor lower case.
I used this code so far but it didn't work as required:
else if ((x[i]) !== (x[i].toUpperCase()) && (x[i]!== x[i].toLowerCase()) ){
x.splice(x[i], 1);
}
This code was for a function that sorts entered strings yet uppercase are sorted first.
Here is the full code, I am also open to understanding better ways to create this function apart from boolean logic and the array methods I used.
function alpha(str){ // United States
var x = str.split(""); // [U,n,i,t,e,d,S,t,a,t,e,s]
var cap = [];
var small = [];
for (var i = 0; i<x.length; i++){
if (x[i] == x[i].toUpperCase()){
cap.push(x[i]);
}
else if ((x[i]) !== (x[i].toUpperCase()) && (x[i]!== x[i].toUpperCase()) ) {
x.splice(x[i], 1);
}
else {small.push(x[i]);}
}
var z = cap.sort();
var y = small.sort();
return z.concat(y).join("");
}
Please note the second else if statement is only useful because the code adds an empty space string at the beginning of the output, I'm not sure where it comes from, so please let me know if you have any idea how to sort this even without using the second else if.
In the ASCII table, upper case letters come first. That's why they come first when you sort alphabetically. Here's a link to a page on Wikipedia that shows the table with the upper case letters appearing first and their numerical equivalents. It's even printable.
Also, I took the liberty of simplifying your code a little. Seems like .splice() was not necessary.
function alpha( str ) {
var x = str.split(""); // [U,n,i,t,e,d,S,t,a,t,e,s]
var cap = [];
var small = [];
var length = x.length;
for (var i = 0; i < length; i++) {
if (x[i] === x[i].toUpperCase()) {
cap.push(x[i]);
} else if (x[i] === x[i].toLowerCase()) {
small.push(x[i]);
}
}
return cap.sort().concat(small.sort()).join("");
}
Maybe explain what you're trying to do? It most likely has been done before in some form and you definitely came to the right place to find an answer.
Is this what you want to do?
var str = "United States";
function alpha(str) {
return str.split('').sort().join('');
}
alert(alpha(str));
In all programming languages (as far as i know), boolean expressions are always evaluated from the left to the right with brackets of course.
So in the following example my_func() is called first, and then if there is the chance that the complete expression becomes true my_other_func() is called
if (my_func() && my_other_func()) {
// I only get here if my_func() AND my_other_func() return true
// If my_func() returns false, my_other_func() is never called
}
The same is true for the "or" operator in the following example
if (my_func() || my_other_func()) {
// I only get here if my_func() OR my_other_func() return true
// If my_func() returns true, my_other_func() is not called
}
So back to your code, in details this part (I reformated it a bit for better readability):
if (x[i] == x[i].toUpperCase()){
// only uppercase here
cap.push(x[i]);
} else if (x[i] !== x[i].toUpperCase() && x[i] !== x[i].toUpperCase()) {
// tested twice the same thing, so Im really sure that its not uppercase :D
// only lowercase here
x.splice(x[i], 1);
} else {
// I will never reach this
small.push(x[i]);
}
Im not sure what you want to do, but I hope the comments help to understand your code.

HTML 5 toggling the contenteditable attribute with javascript

enter code hereI am trying to make something editable online with a function like this
function toggle_editable (div, cssclass) {
var classToEdit = document.getElementsByClassName(cssclass)
for (i = 0;classToEdit.length; i++) {
if (classToEdit[i].contentEditable == false) {
classToEdit[i].contentEditable = true ;
}
if (classToEdit[i].contentEditable == true) {
classToEdit[i].contentEditable = false ;
}
}
}
classToEdit is a collection of HTML elements with the same class name or whatever document.getElementsByClassName(cssclass) returns
when going through the debugger it jumps over the line
classToEdit[i].contentEditable == true
as well as over the line
classToEdit[i].contentEditable == true
and does not execute the code in the braces following the if statements
this works however - meaning it sets the contenteditable property without hesitation
classToEdit.contenteditable = true;
as well as this
classToEdit.contenteditable = false;
(well obviously)
also this seemed to have no effect
classToEdit.contenteditable = !classToEdit.contenteditable
ideas anyone?
ps why is the loop
You've created an infinite loop here:
for (i = 0;classToEdit.length; i++) {
Should be:
for (var i = 0; i < classToEdit.length; i++) {
But, if you say classToEdit.contenteditable = true "works", you've to define "not working/is working" since the snippet doesn't definitely do what you expect it to do, if classToEdit is a HTMLCollection.
It looks like you'd want to toggle contentEditable values, you can do it like this:
for (var i = 0; i < classToEdit.length; i++) {
if (classToEdit[i].contentEditable == false) {
classToEdit[i].contentEditable = true ;
} else { // Notice else here, no need for another check
classToEdit[i].contentEditable = false;
}
}
Or simply without ifs in the loop:
classToEdit[i].contentEditable = !classToEdit[i].contentEditable;
Your current code will switch the value back to it's original in a case the value was false.
HTMLElement.contentEditable returns a string and not a boolean.
Hence, what you want to identify the state of your editable field is:
// Incorrect
classToEdit[i].contentEditable == true
// Coorect
classToEdit[i].contentEditable === 'true'
What's even better if you want to know the state of your fields is to use HTMLElement.isContentEditable
which returns a boolean:
classToEdit[i].contentEditable = !element.isContentEditable
Another way to refactor the above:
function toggleContentEdit() {
var editableFields = document.getElementsByClassName('editable');
[].forEach.call(editableFields, function(field){
var isEditable = field.isContentEditable;
field.setAttribute('contenteditable', !isEditable);
});
};
JSFiddle: http://jsfiddle.net/6qz3aotv/

Multiple OR operators with elem.value.match

I've been writing a javascript function which returns true if the value matches one of about 4 values (just 3 in the example below). The problem is, when I have just two values the function works correctly, but adding a third breaks the code.
I'm pretty new to javascript and I'm guessing there's a much better way of doing this? I've tried searching but found nothing as of yet.
Any help is much appreciated.
function isValid(elem, helperMsg){
var sn6 = /[sS][nN]6/;
var sn5 = /[sS][nN]5/;
var sn38 = /[sS][nN]38/;
if(elem.value.match(sn6 || sn5 || sn38)){
//do stuff
return true;
}else{
return false;
}
}
Edit:
Here's my second attempt with an array:
function isLocal(elem, helperMsg){
var validPostcodes=new Array();
validPostcodes[0]= /[wW][rR]12/;
validPostcodes[1]= /[cC][vV]35/;
validPostcodes[2]= /[sS][nN]99/;
validPostcodes[3]= /[sS][nN]6/;
validPostcodes[4]= /[sS][nN]5/;
validPostcodes[5]= /[sS][nN]38/;
validPostcodes[6]= /[oO][xX]29/;
validPostcodes[7]= /[oO][xX]28/;
var i = 0;
for (i = 0; i < validPostcodes.length; ++i) {
if(elem.value.match(validPostcodes[i])){
// do stuff
return true;
}else{
alert(helperMsg);
elem.focus();
return false;
}
}
}
a || b || c
is an expression that evaluates to a boolean. That means that you're running either match(true) or match(false). You must write it as:
match(a) || match(b) || match(c)
Another option would be to store them in an array and loop over it. That would mean if the number of patterns grew you wouldn't have to change code other than the list of patterns. Another approach, though limited to this situation, might be to change the pattern to one that is equivalent to or-ing the three options together (untested, and I'm a bit rusty on regex):
elem.value.match(/[sSnN][6|5|38]/)
Array based example:
var patterns = [/../, /.../];
for (var i = 0; i < patterns.length; ++i) {
if (elem.value.match(patterns[i])) { return true; }
}
In real code, I would probably format it like this:
function isValid(elem, helperMsg){
var patterns = [/../, /.../],
i = 0;
for (i = 0; i < patterns.length; ++i) {
if (elem.value.match(patterns[i])) {
return true;
}
}
}
That's just a habit though since JavaScript hoists variables to the top of their scope. It's by no means required to declare the variables like that.

Categories