Quick Example:
There is a routed parameter (/Home/:isLoggedIn) that equates to true or false. (/Demo/#/Home/false) and a controller property
this.loggedIn = this.routeParams.loggedIn;
I have a view (Home.html) that has two elements, each with an ng-if attribute.
<div ng-if="home.loggedIn">
Logged In!
</div>
<div ng-if="!home.loggedIn">
Not Logged In...
</div>
If I navigate to /Demo/#/Home/true then the first element displays and the second does not.
If I navigate to /Demo/#/Home/false then the first element does not display NOR does the second one.
I would expect the !home.loggedIn parameter evaluate to true when the value of loggedIn is, in fact, false.
Any advice here?
It is quite obvious that he problem has its root to the fact that routeParams.loggedIn is a string.
So the solution is quite obvious:
// Change that:
this.loggedIn = this.routeParams.loggedIn;
// To this:
this.loggedIn = this.routeParams.loggedIn === 'true';
But why the weird behaviour ?
Why work not showing anything when loggedIn is 'false' ?
Well, here is why:
The ngIf directive uses the following toBoolean() function to convert its value to boolean:
function toBoolean(value) {
if (typeof value === 'function') {
value = true;
} else if (value && value.length !== 0) {
var v = lowercase("" + value);
value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
} else {
value = false;
}
return value;
}
If a string is passed to toBoolean() it converts it to lowercase and checks (among other things) if it equals 'false' (in which case it returns false). This is different than the default JavaScript implementation which interprets any non-empty string as true when casting to boolean.
So, let's examine the two cases for both ngIfs:
loggedIn === 'true'
ngIf1 evaluates home.loggedIn --> 'true' (string)
ngIf1 passes this value through toBoolean()
toBoolean('true') returns true (because it sees a string that can't match with any string considered falsy)
ngIf1 renders its content
ngIf2 evaluates !home.loggedIn <=> !'true' --> false (boolean)
(this happens because any non-empty string happens to evaluate to true)
ngIf2 passes this value through toBoolean()
toBoolean(false) returns false
ngIf2 does not render its content
loggedIn === 'false'
ngIf1 evaluates home.loggedIn --> 'false' (string)
ngIf1 passes this value through toBoolean()
toBoolean('false') returns false (because it sees a string that is considered falsy
ngIf1 does not render its content
ngIf2 evaluates !home.loggedIn <=> !'false' --> false (boolean)
(this happens because any non-empty string happens to evaluate to true)
ngIf2 passes this value through toBoolean()
toBoolean(false) returns false
ngIf2 does not render its content
So, this explains the "weird" behaviour (hopefully in an understandable way).
Problem is likely home.loggedIn is a string, when passed to ng-if it is probably evaluating and doing the conversion from string to bool to get the value "false" into false. In the expression evaluation before the value is passed through if you have !"false" that is actually false since any string is true, negating it becomes false.
Related
Why do logical AND comparison between an empty string and false boolean returns an empty string? and why do logical AND comparison between a string and false boolean returns false?
Example:
'' && true; --> returns ''
'string' && true --> returns true;
'' && false --> returns ''
'string' && false --> returns false;
Question is why javascript behaves this way?
Javascript AND(expr1 && expr2) operator works by returning the expressions based on the logic:
if expr1 is falsy
return expr1
else
return expr2
Falsy values include your empty string(''), null, NaN, undefined, etc. You can read more about it at https://developer.mozilla.org/en-US/docs/Glossary/Falsy.
Also for more info on boolean operators, check out https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators.
The && operator works very simply: if the first value is falsy, it returns the first value, otherwise it returns the second value.
The empty string '' is falsy, so '' && x returns '' for all x. On the other hand, 'string' is truthy, so 'string' && x returns x for all x.
I am a bit confused with this condition:
console.log('' && false) //''
I was expecting it to return false, however it returns ''
but with empty space, it's returning false
console.log(' ' && false) //true
Could someone please explain the reason for this?
My answer was found here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators
Returns expr1 if it can be converted to false; otherwise, returns
expr2. Thus, when used with Boolean values, && returns true if both
operands are true; otherwise, returns false.
So console.log('' && false) //''
because '' can be converted to false (!!'' will return false), it will return ''
What you are receiving out of the first log, '' is not the same condition string. Check this:
console.log('' && false || 'else string')
And you will see it logs the 'else string'. Since your condition has zero length, it goes after the else which does not exist. So it simply shows an emoty string.
Zero length strings are falsy in general and that's why you get false result out of the second one.
"&&" operator evaluates the first operand and proceeds to next operand only if first operand is evaluated to some truthy value or true itself. This evaluation continues until the complete expression is evaluated.
For example, a==b && b>=7 && c==6. In this, only if a==b is true it checks b>=7 and if this evaluates to true then it checks c==6.
Here in your question, '' is an empty string and is a falsy value. Hence, it didn't proceed for the last operand and returned ''. For more information on truthy and falsy values in javascript go through this link: https://www.sitepoint.com/javascript-truthy-falsy/
There is two kind of JavaScript code for investigating empty/full variable:
if(variable == ''){}
if(!variable){}
I tested both of them, and I achieved identical result. Now I want to know, (first) are they equivalent? And (second) which one is more standard for checking empty/full variable?
var variable1 = 'string';
var variable2 = 12;
var variable3 = true;
if(variable1 == ''){alert('empty-one');}
if(variable2 == ''){alert('empty-one');}
if(variable3 == ''){alert('empty-one');}
if(!variable1){alert('empty-two');}
if(!variable2){alert('empty-two');}
if(!variable3){alert('empty-two');}
As you see, there is no alert.
First is not standard, it only works for defined empty string.
Other will work if value is not truthy ( means something meaningful)
e.g var a;
a == '' will give false result
! a will produce true
e.g. var a = null;
a == '', // false
! a // true
var a = false;
a == '' // fase
! a // true
var a = NaN
a == '' // false
! NaN // true
true == 'true' // false, Boolean true is first converted to number and then compared
0 == '' // true, string is first converted to integer and then compared
== uses The Abstract Equality Comparison Algorithm to compare two operands
For more detail visit http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3
In javascript null,'',0,NaN,undefined consider falsey in javascript.
In one sense you can check empty both way
But your first code are checking is it ''
and your 2nd condition is checking is your value are one of them (null,'',0,NaN,undefined)
In my view your 2nd condition is better then first as i don't have to check null,'',0,NaN,undefined seperately
No they are not equivalent. In case first it checks whether the value of variable is equal to the empty string('') or not. So case first will be true iff variable's value is ''. But second case will be true for all the values which are falsey i.e. false, 0, '', null, undefined.
In javascript we use shortand notation if(input){} to check for empty or null input. We will get false for Null, Undefined, false, 0, NAN, "". My requirements is that I want to get true for any number including zero so I have created a method as follows
function checkFalseExceptZero(value){
if( value !== undefined && value !== null && value !== false && value !== "" && value.length !== 0 ) return true;
else return false;
}
I have added all possible checks in the above method to get the desired result. I am curious if there is any quick, sweet, short or more robust approach to achieve the same?
A simple to understand answer. The three equal signs in JS will not convert type to check if the values equal unlike the two equal signs.
0 == false //true
0 === false //false, because 0 is a number and false is a boolean
Therefore, the answer, if you want to put it inside a function:
JS:
function isNumber(v) {
return typeof v === "number"
}
The function will check the type of the variable. So it is not actually comparing the value to determine the result. The function will only return true if the type of the variable is called number.
Test runs:
isNumber(0) //true
isNumber(false) //false
isNumber("0") //false
isNumber(undefined) //false
In case you want to know, typeof variable will return a string.
My requirements is that I want to get true for any number including
zero so I have created a method as follows
function checkFalseExceptZero(value){
if ( variable.constructor === Array) return !!value.length;
return value === 0 || !!value;
}
This a shorter version of your function. This returns true only when value is 0 or a trully value.
So :
checkFalseExceptZero(null) ==> false;
checkFalseExceptZero(undefined) ==> false;
checkFalseExceptZero(false) ==> false;
checkFalseExceptZero("") ==> false;
checkFalseExceptZero(0) ==> true;
checkFalseExceptZero([]) ==> false;
checkFalseExcpetZero([1]) ==> true;
For any valid number, including 0, JavaScript already exposes the isFinite function. This returns false for all non-numbers, as well as for infinite and NaN
Examples (excerpt from the linked mdn page):
isFinite(Infinity); // false
isFinite(NaN); // false
isFinite(-Infinity); // false
isFinite(0); // true
isFinite(2e64); // true
isFinite("0"); // true, would've been false with the
// more robust Number.isFinite("0")
Can you explain why the if condition doesn't work without the eval function:
var myBoolean= document.getElementById("someBoolean").value; //This is a 'false'
if(myBoolean)
{
alert(Your boolean is True); //This condition always getting executed even though myBoolean is false;
}
if(eval(myBoolean))
{
alert("You will never see this alert bcoz boolean is false");
}
In Javascript the following values are treated as false for conditionals:
false
null
undefined
The empty string ''
The number 0
The number NaN
Everything else is treated as true.
'false' is none of the above, so it's true.
The string 'false' evaluates to the boolean true
This is because it's not actually a boolean, it's a the string 'false'. When you convert a string to a boolean, '' is false and anything else is true.
You check if it's equal to the string 'false' (or 'true') or not.
var myBoolean = 'false'; // (string)
myBoolean = myBoolean !== 'false'; //false (boolean)
'false' == true, crazily enough because of JavaScript's implicit type coercion. Check out these other examples from Crockford's The Elements of JavaScript Style.
'' == '0' // false
0 == '' // true
0 == '0' // true
false == 'false' // false
false == '0' // true
false == undefined // false
false == null // false
null == undefined
// true
' \t\r\n ' == 0 // true
You could solve this particular problem by changing your code to something like
var myBoolean = document.getElementById("someBoolean").value === "true"
Also, it is almost always better to use !! and === rather than ! and ==
document.getElementById("someBoolean") does not return a boolean true/false it returns an element or undefined / null
you could reverse your logic and get the expected result:
if(!myBoolean)
{
alert('This element does not exist');
}
if(!eval(myBoolean))
{
alert("Do not know why you would ever want to do this");
// you could do typeof()
}
Try:
var myBoolean= document.getElementById("someBoolean").value; //This is a 'false'
if(myBoolean != "false")
{
alert(Your boolean is True); //This condition always getting executed even though myBoolean is false;
}
Like others have said, a string isn't a boolean value, so using it as though it was will give you a logical error.
A string IS a boolean truth value according to ECMA
var a = ""<br/>
a&&false //-> false<br/>
a||false //-> "" (truthy)<br/>