Coffeescript ternary if-statement wrong logic - javascript

I have a pretty much simple logic in a return function, but it doesn't work as expected. Of course I can make the code slightly longer and solve the issue, but I want it to be as small as possible.
Here is my code:
#Return title if exists or false otherwise
getPageTitleFromMainContent = (mainContent) ->
mainContent.find('#pageTitle') ?.length ?= false
if y = (getPageTitleFromMainContent $("#mainContent"))
y.css color:red
As you see, if it finds the #pageTitle in #mainContent, it should make it red. But the function doesn't return the #pageTitle if found, it returns .length.
From js2coffee.org I see that the code is compiled into:
var getPageTitleFromMainContent, y;
getPageTitleFromMainContent = function(mainContent) {
var _ref, _ref1;
return (_ref = mainContent.find('#pageTitle')) != null ? (_ref1 = _ref.length) != null ? **_ref1 : _ref.length = false : void 0;**
};
if (y = getPageTitleFromMainContent($("#mainContent"))) {
y.css({
color: red
});
}
And it should be _ref : _ref.length = false : void 0;, not _ref**1** : _ref.length = false : void 0; .
http://jsfiddle.net/X8VjJ/1/
Thank you!

if it finds the #pageTitle in #mainContent, it should make it red
You can accomplish this with the much simpler:
$('#mainContent #pageTitle').css(color: 'red')
Since, if it doesn't find #pageTitle in #mainContent, it will try to change the css of an empty set of elements -- a no-op.
The code as you've presented it doesn't really make sense. ?. is unnecessary, as the jQuery selector will not return null or undefined if it doesn't match; it will return an empty set of elements. So it will always be returning length, which will always be a number, so the assignment will never execute, since it depends on length returning null or undefined. Which is good, since you probably don't want to set the length of the elements to false.
Finally, this isn't the ternary if statement. CoffeeScript's ternary if statement looks like this: if foo then bar else baz.

Not sure that code makes sense. You're effectively trying to assign TO the length property, unless length is defined. If it is defined, it simply returns the length property. Looks like the code and behaviour is correct, but your understanding of the existential operator and return values is wrong. If you want to return the found element you probably need to disconnect it from the length check.
Maybe something like:
getPageTitleFromMainContent = (mainContent) ->
arr = mainContent.find('#pageTitle')
if arr.length then arr else false
As Ian explained in his more elegant answer, you do not need to use the existential operator on arr (assuming jquery), since it will always be an array of elements (with zero length if not found).

Related

How to Check the variable value is [""] in JavaScript

Example:
When I check a variable containing this value [""] it returns false.
var th=[]
th.push("");
if($("#multiselect").val()==th)
It returns always false.
Thank you.
Edit 1:
changed Var to var. It was a typo.
Edit 2:
Actually, the problem I faced was I was trying to get the value from a multi-select input. The multi-select input sometimes returns values as [""] even I haven't selected any values basically it's a plugin. So I was confused and I thought [""] is a fixed primitive value like 1, 10, "bla blah",.. So I tried to compare it with the same array as the right-hand side of the '=' operator.
It was stupid. Now I posted the solution to my problem and I explained my stupidity.
there are two things:
Change Var to var
You can use includes method of Array as:
var th = [] <==== chnage Var to var
th.push("");
if(th.includes($("#multiselect").val())) { <=== you can use includes method of array
// DO whatever you want
}
Make sure var is lowercased.
You are accessing th as an array, so you’ll need to specify the index of the value you are checking: th[0]
Use triple equals, too: .val()===th[0]
Double check the jquery docs if you’re still running into trouble.
Happy coding!
A couple of things to consider:
You have a typo in the code above; var is valid; Var is invalid.
Browser will aptly complain to solve this typo.
You are comparing an array to DOM value; this will always be false.
DOM is a costly process. Unless the value associated is dynamic, its better to read once, store value into a variable and continue processing instead of reading from DOM always.
You could choose to try something on these lines:
let arr = [1,2,3,4];
let domValue = $("#multiselect").val();
arr.push(5);
arr.map((el, ix) => {
if el === domValue return true; //or choose to do something else here.
});
var th=[]; //It is var not Var
th.push("");
if($("#multiselect").val()==th[0]) // change th to th[0]
I am unable to comment so having to use an answer for now. Are you trying to check if an array has any values? If so you can use
if(th.length){
// do something
}
If you want to check a normal variable for empty string you can simply use
if(th == “”){
//do something
}
I found the solution after a couple of days when I posted this question. Now I can feel how stupid this question was.
Anyway, I'm answering this question so it might help others.
Answer to my question:
When two non-primitive datatype objects(which is the Array here) are compared using an assignment operator, it compares its reference of the object. So the object creation of both arrays would be different. If I want to check the array has [""] value, I should do something like the below.
function isArrValEmptyCheck(value) {
return !value || !(value instanceof Array) || value.length == 0 || value.length == 1 && value[0] == '';
}
console.log(isArrValEmptyCheck([""]));//returns true
console.log(isArrValEmptyCheck(["value1"]));//returns false
Sorry for the late response. Thanks to everyone who tried to help me.

Curious how others would create a fallback for this: som var = number 0 || false?

so, I came across a bug and thought it was interesting. Once I sat and thought about it for 5 seconds, it made sense but curious how one would get past it in the future.
so, I have some hashes set up in an obj. (snippet of code from a larger obj).
someBigObj : {
someObj : {
item1 : 0
item2: 1
item4: 2
item3: 3
}
}
So, I set it up this way because I need to reference an Array position that corresponds to data that is associated with those items.
So, if I happen to reference item1 -- look what we get.
var varReference = someBigObj.someObj['item1'] || false;
// which is equivalent to
var varReference = 0 || false;
see what happens there? that reference is 0. So varReference is always false. I actually want the number 0 in this case because I need to access an array element. I think stringing it is odd to me, because it is not a string, but rather an integer. How can I still use this fallback of || false, but actually get the number 0 to be seen as a valid value.
Note: I understand I can explicitly test etc.. just curious if there is a a shortcut or native js (that I am unaware of) that solves my solutions. figured something like would work but didn't.
Number(0) || false
additional note: I ended not putting a || false, as even if it it's not referenced correctly there is no error. So it doesn't actually matter, but I always like to have fallbacks so that is why I am curious.
If you want falsey values to pass your test, then the test probably needs to look explicitly for undefined, not just a falsey value.
var varReference = someBigObj.someObj['item1'] !== undefined ? someBigObj.someObj['item1'] : false;
Keep in mind that lots of legitimate values are falsey such as 0, "", null (and others).
You can use an inline if to check if your value is undefined explicity.
var varReference = (typeof(someBigObj.someObj['item1']) !== 'undefined') ? someBigObj.someObj['item1'] : false;
Instead of trying to look at the value in the property (and its falsiness, which fails you sometimes), you should check whether the property exists in the object with the in operator:
var varReference = 'item1' in someBigObj.someObj
? someBigObj.someObj['item1']
: false;
which can be simplified to
var varReference = 'item1' in someBigObj.someObj && someBigObj.someObj['item1'];

JavaScript Short Circuit Logic

After seeing some examples online, I've collected two different explanations:
Ex: var x = A || B;
If A exists and B does not, left side is returned.
If A exists and B exists , return right side (last evaluated value).
Based on that logic, I would assume that x would return: v.item(0).click(). But when testing it x first returned B then A, aka fired B then fired A as well. Why? (http://jsfiddle.net/nysteve/QHumL/59/)
HTML:
<div class="indeed-apply-button" onclick="alert('BOOM BUTTON');">boo</div>
<div class='view_job_link' onclick="alert('BOOM LINK');">boo</div>
JavaScript
var v = document.getElementsByClassName('view_job_link');
var i = document.getElementsByClassName('indeed-apply-button');
var x = v.item(0).click() || i.item(0).click();
EDIT 1:02 PM 10/10/2013
Did not mention my true intentions, but based on the answer and discussion, my goal was essentially to convert the following piece of code into the JavaScript code I originally mentioned.
var v = document.getElementsByClassName('view_job_link');
var i = document.getElementsByClassName('indeed-apply-button');
if(v){v.item(0).click();}
else if(i){i.item(0).click();}
else{}
In the code above, how would you read if(v){v.item(0).click();} vs. the short-circuit?
Neither of your two descriptions are accurate.
var x = A || B;
What that does is:
Evaluate "A". Call the result VA.
If VA is not null, undefined, 0, NaN, false, or the empty string, then the value of the overall expression is VA and evaluation stops.
Evaluate "B". Call the result VB. That value, VB, is the value of the expression.
Your test code first tests the return value of calling the "click" function on the first element and then the second. Those functions both return undefined, so the subexpressions on both sides of the || are evaluated. That is, the first call gets VA and it's undefined, so that means that the other side will be evaluated too, and that'll be the value of the expression. (It's going to come out undefined.)
edit — OK now that you've added more to the answer, I think I see what you're up to.
In your actual code (or, I guess, the sample code that's closer to reality), you've got:
if(v){v.item(0).click();}
else if(i){i.item(0).click();}
else{}
That means something quite different than:
var x = v.item(0).click() || i.item(0).click();
Note that in the if statement version, it's explicitly checking "v". A test like that will perform a "truthy/falsy" test on the value of "v". In this case, it's really checking to make sure that "v" isn't either null or undefined. In the || version, however, there's no such explicit test for the "goodness" of variable "v"; it's just used directly. (If it happens to be null there, that'd result in a runtime error.)
A version of the actual code using || and && is possible, but in my opinion the existing code is clearer. However, just for discussion purposes, you could replace the if version with:
v && (v.item(0).click(), true) || i && i.item(0).click();
Personally I think that looks kind-of ugly.

Why is angular.isNumber() not working as expected?

It appears as if AngularJS's angular.isNumber is not working. It doesn't work with strings that are numbers. Am I doing something wrong? Should I just use isNaN()?
angular.isNumber('95.55') == false
angular.isNumber('95.55' * 1) == true
angular.isNumber('bla' * 1) == true
angular.isNumber(NaN) == true
I need something to see if a string is a number (when it actually is) and angular.isNumber() won't let me do that unless I multiply by 1, but if I do that then it will always be true. Also NaN is not a number (by definition) and so should return false.
In JavaScript, typeof NaN === 'number'.
If you need to recognise a String as a Number, cast it to Number, convert back to String and compare this against the input, for example.
function stringIsNumber(s) {
var x = +s; // made cast obvious for demonstration
return x.toString() === s;
}
stringIsNumber('95.55'); // true
stringIsNumber('foo'); // false
// still have
stringIsNumber('NaN'); // true
I was working on the same problem and I was trying to work around that edge case. So I created a slightly different approach.
FIDDLE
function isStringNumber(str) {
var parsed = parseFloat(str);
var casted = +str;
return parsed === casted && !isNaN(parsed) && !isNaN(casted);
}
Use it as below,
angular.isNumber(eval('99.55'))
for other expressions also we may use eval(input).
Note: eval() is a javascript method
Edit:
It is not recommended to use eval(), as document says Never use eval()!
Thanks #Diogo Kollross

jQuery has conditional

Trying to write a conditional with jQuery that basically states, if div.gathering does not contain a.cat-link then do the following. I have tried the following but it doesn't seem to work. Can anyone shed some light on this?
if($("div.gathering:contains('a.cat-link')")){
$(".gathering").append("<a href='#"+data[i]["categories"][0]["category_id"]+"div' class='cat-link' id='"+data[i]["categories"][0]["category_id"]+"' rel='external'>"+data[i]["categories"][0]["category_name"]+"<br />");
}
How about this :
if($("div.gathering").find("a.cat-link").length == 0){
// Conditional statement returned TRUE
}
jQuery selectors return arrays of objects that matched the given selector. This is why we use the length property.
The method that you used - $("div.gathering:contains('a.cat-link')")
would return an empty array and when testing against any object that actually exists (even if it is an empty array) JavaScript will return true.
Example -
var nateArr = [];
if (nateArr){
// Do the dishes...
}else{
// Eat some waffles...
}
If you test this for yourself you will never stop washing those dishes because even though the nateArr contains zero elements it still exists therefore the conditional statement will always return true.
And your fingers will go all wrinkly
try this....
$("div.gathering:not(:contains(a.cat-link))")
.append("<a href='#"+data[i]["categories"][0]["category_id"]+"div' class='cat-link' id='"+data[i]["categories"][0]["category_id"]+"' rel='external'>"+data[i]["categories"][0]["category_name"]+"<br />")
this will only return the div with class gathering which does not have a.cat-link....
hope this helps....

Categories

Resources