javascript passing the result of a boolean comparison confusion - javascript

I've been working through some text book to learn web development and i've become confused on an example. The example creates a meter element and fills it with some attributes. There is then some javascript to check for browser support for the tag. The part where i'm confused is after the first expression returns either true or false for the support, shouldn't there be a check for if true or false was returned on the following if statement? also as an aside, when the create element builds the element does is give it default values, or grab values from an existing meter in the html.
The check for support is as follows.
var noMeterSupport = function(){
return(document.createElement('meter').max === undefined);
}
the next part that builds the meter if the support isn't found is below. This is where i become confused as it seems to take either value and continue without checking if it was true or false.
if (noMeterSupport()) {
var fakeMeter, fill, label, labelText, max, meter, value;
value = meter.attr("value");
meter = $("#pledge_goal");
max = meter.attr("max");
labelText = "$" + meter.val();
fakeMeter = $("<div></div>");
fakeMeter.addClass("meter");
label = $("<span>" + labelText + "</span>");
label.addClass("label");
fill = $("<div></div>");
fill.addClass("fill");
fill.css("width",(value / max * 100) + "%");
fill.append("<div style='clear:both;'><br></div>");
fakeMeter.append(fill);
fakeMeter.append(label);
meter.replaceWith(fakeMeter);
}

The body of the if is only executed if noMeterSupport() returns true. The condition in an if statement requires something "truthy", i.e. something that can be interpreted as true or false. Since the function returns a boolean value, that is sufficient. (See first Google hit for truthiness javascript, which is a good explanation.)
EDIT: Forgot about your second question. When a new element is created with document.createElement, it does indeed get default values. In your example, the default value of max for a <meter> is 1.

if (noMeterSupport()) { checks the return value. It means exactly the same as this:
var supported = noMeterSupport();
if(supported) {

I hope that I understand your question correctly and will try to answer it.
So you would expect something like this:
if (noMeterSupport() == true)
Actually, this is equivalent to this:
if (noMeterSupport())
And if you want to check false:
if (noMeterSupport() == false)
This is equivalent to:
if (!noMeterSupport())

This statement will make the function either return true or false:
return(document.createElement('meter').max === undefined)
basically it would be synonymous with writing:
if(document.createElement('meter').max === undefined) {
return true;
} else {
return false;
}
That makes the value of noMeterSupport() either true or false.

var noMeterSupport = function(){
return(document.createElement('meter').max === undefined);
}
noMeterSupport returns the result of the comparison document.createElement('meter').max === undefined.
The comparison will be either true or false, ok?
So, now, when you do
if (noMeterSupport()) { /*then do something*/}
is like saying
if (/*the result of noMeterSupport() is true*/) {/*then do something*/}
So, this if statement will only run if noMeterSupport returns true

var noMeterSupport = function(){
return(document.createElement('meter').max === undefined);
}
This section of code is not actually doing the check, it is defining a function called noMeterSupport.
The code is not actually run until the function is called. It is called by adding () to the function name.
noMeterSupport()
Your if() statement is where it is being called as it the brackets.

You expect a boolean condition inside the if statement:
if(<boolean_condition>)
{
...
}
The noMeterSupport() is actually returning true or false, so the
if(noMeterSupport())
is converted to if(true) or if(false)
depending on the result of the document.createElement('meter').max === undefined evaluation.
You are receiving a boolean condition and the if statement works fine.

As a beginner, there's two points to quickly learn in programming :
The comparison operators == and === not only do the comparison, but returns in fact the result of this comparison (you can place it in var to test)
var bool = 1 === 2;
console.log(bool); // will print false
The test if(boolean === true) is equivalent to if(boolean), and the test if(boolean === false) is equivalent to if(!boolean)

Related

Check if elements are part of wrapper [duplicate]

How can I check if one DOM element is a child of another DOM element? Are there any built in methods for this? For example, something like:
if (element1.hasDescendant(element2))
or
if (element2.hasParent(element1))
If not then any ideas how to do this? It also needs to be cross browser. I should also mention that the child could be nested many levels below the parent.
You should use Node.contains, since it's now standard and available in all browsers.
https://developer.mozilla.org/en-US/docs/Web/API/Node.contains
Update: There's now a native way to achieve this. Node.contains(). Mentioned in comment and below answers as well.
Old answer:
Using the parentNode property should work. It's also pretty safe from a cross-browser standpoint. If the relationship is known to be one level deep, you could check it simply:
if (element2.parentNode == element1) { ... }
If the the child can be nested arbitrarily deep inside the parent, you could use a function similar to the following to test for the relationship:
function isDescendant(parent, child) {
var node = child.parentNode;
while (node != null) {
if (node == parent) {
return true;
}
node = node.parentNode;
}
return false;
}
I just had to share 'mine'.
Although conceptually the same as Asaph's answer (benefiting from the same cross-browser compatibility, even IE6), it is a lot smaller and comes in handy when size is at a premium and/or when it is not needed so often.
function childOf(/*child node*/c, /*parent node*/p){ //returns boolean
while((c=c.parentNode)&&c!==p);
return !!c;
}
..or as one-liner (just 64 chars!):
function childOf(c,p){while((c=c.parentNode)&&c!==p);return !!c}
and jsfiddle here.
Usage:
childOf(child, parent) returns boolean true|false.
Explanation:
while evaluates as long as the while-condition evaluates to true.
The && (AND) operator returns this boolean true/false after evaluating the left-hand side and the right-hand side, but only if the left-hand side was true (left-hand && right-hand).
The left-hand side (of &&) is: (c=c.parentNode).
This will first assign the parentNode of c to c and then the AND operator will evaluate the resulting c as a boolean.
Since parentNode returns null if there is no parent left and null is converted to false, the while-loop will correctly stop when there are no more parents.
The right-hand side (of &&) is: c!==p.
The !== comparison operator is 'not exactly equal to'. So if the child's parent isn't the parent (you specified) it evaluates to true, but if the child's parent is the parent then it evaluates to false.
So if c!==p evaluates to false, then the && operator returns false as the while-condition and the while-loop stops. (Note there is no need for a while-body and the closing ; semicolon is required.)
So when the while-loop ends, c is either a node (not null) when it found a parent OR it is null (when the loop ran through to the end without finding a match).
Thus we simply return that fact (converted as boolean value, instead of the node) with: return !!c;: the ! (NOT operator) inverts a boolean value (true becomes false and vice-versa).
!c converts c (node or null) to a boolean before it can invert that value. So adding a second ! (!!c) converts this false back to true (which is why a double !! is often used to 'convert anything to boolean').
Extra:
The function's body/payload is so small that, depending on case (like when it is not used often and appears just once in the code), one could even omit the function (wrapping) and just use the while-loop:
var a=document.getElementById('child'),
b=document.getElementById('parent'),
c;
c=a; while((c=c.parentNode)&&c!==b); //c=!!c;
if(!!c){ //`if(c)` if `c=!!c;` was used after while-loop above
//do stuff
}
instead of:
var a=document.getElementById('child'),
b=document.getElementById('parent'),
c;
function childOf(c,p){while((c=c.parentNode)&&c!==p);return !!c}
c=childOf(a, b);
if(c){
//do stuff
}
Another solution that wasn't mentioned:
Example Here
var parent = document.querySelector('.parent');
if (parent.querySelector('.child') !== null) {
// .. it's a child
}
It doesn't matter whether the element is a direct child, it will work at any depth.
Alternatively, using the .contains() method:
Example Here
var parent = document.querySelector('.parent'),
child = document.querySelector('.child');
if (parent.contains(child)) {
// .. it's a child
}
You can use the contains method
var result = parent.contains(child);
or you can try to use compareDocumentPosition()
var result = nodeA.compareDocumentPosition(nodeB);
The last one is more powerful: it return a bitmask as result.
Take a look at Node#compareDocumentPosition.
function isDescendant(ancestor,descendant){
return ancestor.compareDocumentPosition(descendant) &
Node.DOCUMENT_POSITION_CONTAINS;
}
function isAncestor(descendant,ancestor){
return descendant.compareDocumentPosition(ancestor) &
Node.DOCUMENT_POSITION_CONTAINED_BY;
}
Other relationships include DOCUMENT_POSITION_DISCONNECTED, DOCUMENT_POSITION_PRECEDING, and DOCUMENT_POSITION_FOLLOWING.
Not supported in IE<=8.
I came across a wonderful piece of code to check whether or not an element is a child of another element. I have to use this because IE doesn't support the .contains element method. Hope this will help others as well.
Below is the function:
function isChildOf(childObject, containerObject) {
var returnValue = false;
var currentObject;
if (typeof containerObject === 'string') {
containerObject = document.getElementById(containerObject);
}
if (typeof childObject === 'string') {
childObject = document.getElementById(childObject);
}
currentObject = childObject.parentNode;
while (currentObject !== undefined) {
if (currentObject === document.body) {
break;
}
if (currentObject.id == containerObject.id) {
returnValue = true;
break;
}
// Move up the hierarchy
currentObject = currentObject.parentNode;
}
return returnValue;
}
Consider using closest('.selector')
It returns null if neither element nor any of its ancestors matches the selector. Alternatively returns the element which was found
try this one:
x = document.getElementById("td35");
if (x.childElementCount > 0) {
x = document.getElementById("LastRow");
x.style.display = "block";
}
else {
x = document.getElementById("LastRow");
x.style.display = "none";
}
TL;DR: a library
I advise using something like dom-helpers, written by the react team as a regular JS lib.
In their contains implementation you will see a Node#contains based implementation with a Node#compareDocumentPosition fallback.
Support for very old browsers e.g. IE <9 would not be given, which I find acceptable.
This answer incorporates the above ones, however I would advise against looping yourself.

test for null not working

I have a an onclick function, inside this function I want to create a condition for the way some elements are shown in the textarea. added this in the function:
bPlace = bookForm.txtPlace.value;
if (bPlace="null") {
bPlace="!."
}
bookForm.myText.value = bPlace
according to this condition when the value in txtPlace in myForm is not null it should show anything the user puts in. But when I test it, when I type something, instead of showing that, it still shows the (( !. )) in the textarea.
I should say I used "Undefined" instead of Null and still the same thing happened
Can you please tell me what am I doing wrong?
The problem is you are using assignment operator instead of comparision operator
The statement bPlace="null" will assign the string null to bPlace and will return it, which is a truthy value so the if block will always get executed.
bPlace = bookForm.txtPlace.value;
if (bPlace == "null") {
bPlace = "!."
}
bookForm.myText.value = bPlace
But since bPlace is a input value, I think what you are trying to do is if the input is left blank you want to put a default value in that case you can check
bPlace = bookForm.txtPlace.value;
if (!bPlace) {
bPlace = "!."
}
bookForm.myText.value = bPlace
Demo: Fiddle
Which can be further shorten to
bookForm.myText.value = bookForm.txtPlace.value || '!.';
Demo: Fiddle

If-statement fail in javascript

For several hours now am I trying to make a simple game, but one if-statement is failing:
function checkDiagonaal() {
if (document.getElementById("11").src.indexOf("o.png") &&
document.getElementById("22").src.indexOf("x.png") &&
document.getElementById("33").src.indexOf("o.png"))
{
winnaar = true;
}
}
The condition is not true, yet the variable winnaar is set on true. I don't see what I am doing wrong. Very probably just a little mistake.
I also tried this code:
if(document.getElementById("11").src === "images/o.png")
but this returns false (even when the condition is true). I would like to know why?
Use ...indexOf(...) >= 0 in such conditions.
indexOf returns -1 when the value is not found, -1 is truthy
From the MDN(great resource!):
"The indexOf() method returns the index within the calling String
object of the first occurrence of the specified value [...] returns -1
if the value is not found."
When statements get big they become a bit unreadable, it might be fine now, but if you need to add more checks, I would suggest a different approach:
function checkDiagonaal() {
var ids = [11,22,33];
var strs = ['o.png','x.png','o.png'];
var winnar = ids.every(function(id,i) {
return document.getElementById(id).src.indexOf(strs[i]) > -1;
});
}

If statement is not working properly

I'm trying to change the condition in which data is written to a table. I noticed a strange result when trying to change this: it seems WriteToTable function would runno matter what if condition I subjected it to. To test this I did the following:
var TestThis=0;
if (TestThis=1000){
WriteToTable(iPlaceDisplayNum, place.name, place.rating, xScoreFinal, iProspect, place.url, place.formatted_phone_number);
alert ('This alert should not be displaying.');
}
The function will still execute and the alert will be still be displayed when the script runs. I'm not sure why?
Here's the rest of the function, the problem is towards the bottom:
function printme(place, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
if (typeof place.reviews !== 'undefined') {
var xScore = 0;
var xGlobal = 0;
for (var i = 0; i < place.reviews.length; i++) {
reviews = place.reviews[i];
for (var x = 0; x < reviews.aspects.length; x++) {
aspectr = reviews.aspects[x];
xScore += aspectr.rating;
xGlobal++;
}
}
var xScoreFinal = (xScore / xGlobal);
}
if (typeof xScoreFinal !== 'undefined') {
iPlaceDisplayNum++;
var iProspect;
if (xScoreFinal < 2.3) {
iProspect = 'Yes';
}
//Not sure what's going on here
var TestThis=0;
if (TestThis=1000){
WriteToTable(iPlaceDisplayNum, place.name, place.rating, xScoreFinal, iProspect, place.url, place.formatted_phone_number);
alert ('This alert should not be displaying.');
}
}
}
}
You are assigning a value to your variable in your if condition check. Your TestThis variable is being assigned value 1000, which will be true after being converted to boolean by JavaScript. That's why your function is being always executed. You can read more about the automatic type conversion here.
Now to fix your code, change this -
if (TestThis=1000)
to this -
if (TestThis == 1000)
or if you don't want automatic type conversion -
if (TestThis === 1000)
Sometimes people like to reverse the values in the comparison, in the following way -
if (1000 === TestThis)
This is called a Yoda Condition (yeah, named after the Grand Jedi Master Yoda) . The benefit is that in case someone mistakenly puts only a single equal, it will result in an error as you cannot assign anything to a constant. I have never used it personally though (and probably never will because I find it rather unconventional).
JavaScript allows you to assign a value in a conditional, so this TestThis=1000 results to 1000 and in a conditional statement positive numbers (actually anything not 0) result to an evaluation to true.
To make it a conditional, you should do TestThis===1000 (and you should almost always use the === over the == as the === forces an actual comparison of the two and doesn't try to convert one part of the conditional to equal the other.)
You can also do 1000 === TestThis (or conversly 1000 == TestThis) Some people say this is bad coding, because it's difficult to read. I'll leave that up to you to decide, but this absolutely won't allow you to accidentally assign a value in the conditional because you can't assign a value to 1000.
In the if statement, you're setting TestThis to 1000, rather than comparing it to 1000. The = operator returns the value that was set, which evaluates to true because it is not undefined, 0, or null. You simply need to use the == operator.
if(TestThis == 1000)
if (TestThis == 1000)
Change like this.
For comparing equality in if you must have ==
Change:
if (TestThis=1000)
To:
if (TestThis==1000)
You're actually assigning to TestThis which will return true and execute the conditional block.

What does this (useless?) javascript code do?

While debugging a javascript code that uses jQuery I found the following code:
[0, 0].sort(function()
{
baseHasDuplicate = false;
return 0;
});
By my understanding of javascript this code will sort array containing two zeroes with comparison function that will always set a global variable and will return equality, which has same effect as baseHasDuplicate = false;.
Coming from a valued source I think I missed something.
Did I miss something or is this a programming fail?
As you can see here (chinese), this code might be used to test for Chrome. EDIT: see below for the complete story..
As explained in the article, what happens is that Chrome optimizes the ".sort(...)" method in such a way that the [0, 0].sort(...) call won't execute the given comparison function.
From the article, Chrome's implementation of ".sort(...)" is something like:
function sort(comparefn) {
var custom_compare = (typeof(comparefn) === 'function');
function Compare(x,y) {
if (x === y) return 0;
if (custom_compare) {
return comparefn.call(null, x, y);
}
...
}
As 0 === 0 is true, it won't call comparefn.
In the case of jQuery, it won't set the global variable baseHasDuplicate to false.
EDIT: if you browse Sizzle's source code, here for example (go to the yellow section under "Sizzle CSS Selector Engine", called "Sizzle variables"), you will find the following explanation:
var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
done = 0,
toString = Object.prototype.toString,
hasDuplicate = false,
baseHasDuplicate = true;
// Here we check if the JavaScript engine is using some sort of
// optimization where it does not always call our comparision
// function. If that is the case, discard the hasDuplicate value.
// Thus far that includes Google Chrome.
[0, 0].sort(function(){
baseHasDuplicate = false;
return 0;
});
Looks demystified!

Categories

Resources