-
Notifications
You must be signed in to change notification settings - Fork 479
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixed :else in section when iterating over empty array. #127
Conversation
The "No friends" 101 example from dust documentation was actually not working
@vybs we have discussed this in another issue, I could not find it. do u remember? |
@jairodemorais - not sure what there is to discuss. It clearly breakes this verbatim sentence from documentation:
Either this needs to be merged or the documentation needs to be changed. |
@zzen easy ! If there is anything wrong in documentation lets correct it. http://blogs.hbr.org/taylor/2012/08/its_more_important_to_be_kind.html |
@vybs - nothing wrong with the documentation in my view, hence the pull-request to fix the implementation. @jairodemorais - I've read the issue, thanks for the link. In my view, fixing the documentation (and keeping the existing, broken behavior) is the wrong way to fix the problem. I'd love to hear the reasoning behind why current status-quo is more reasonable. I don't think "there is a workaround with more convoluted syntax" is a good reason. |
Not a great argument but empty arrays are truthy in js |
@jimmyhchan - ok, that's a reasonable way to look at it. However if dust aligned itself with how JS evaluates stuff, then (?foo} for foo=0 would evaluate as false, which it unfortunately doesn't at this point... So clearly compatibility with true/false evaluations in JS is not the design intent. In my view, if you're writing a template to iterate over all items in an array, then providing alternative content for empty array is the most typical job, most intuitive behavior - and the else fork is an elegant way to solve it. The fact that this is the way it has been documented not only in the LinkedIn fork but also in the original @akdubya docs - speaks volumes about it being intuitive behavior. I'm just puzzled that nobody has not noticed all that time that the implementation doesn't actually match that behavior. Is it years since @akdubya wrote it? |
Ok after some digging deeper ( updated the wiki ) There are two other special section notations that provide conditional testing:
Note that if "name" does exist, it is evaluated as follows (e.g "" or ' ' will evaluate to false, false will evaluate to false of course, but 0 evals to true, so does, "0", "false" will evaluate to true). Also note that empty [] is evaluated to false and empty {} is evaluated to true the ? tag. Since both pass the "exists" check and are empty, it should have been treated the same way. Next, lets look at how the section tag works with exists and truthy/falsy evaluation Template:
JSON:
This renders html as expected:
However if we change the friends array to be empty,
the {:else} block does not trigger, we are instead left with an empty "ul" element. You can achieve the desired behaviour by doing this,
But this is really odd. The {#} does not behave the same as the {?}. {?} treats [] as falsy and executes the else block. Why? {#} treats the [] as exists, but does not execute either the section body nor the else block ( A BUG ) We need to fix this : atleast to be consistent between ? and # and then IMO # not executing either blocks is a real bug agreed |
@@ -128,6 +128,13 @@ var grammarTests = [ | |||
message:"should test the else block" | |||
}, | |||
{ | |||
name: "empty_else_block", | |||
source: "{#foo}full foo{:else}empty foo{/foo}", | |||
context: { foo: []}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we add a few more tests for completeness
to make sure both ? and # behave the same way
- 0
- "0"
- true
- false
- []
- {}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should fix the problem more upstream where dust seems to be treating numbers as string literals...i.e. 0 doesn't evaluate to false, which leads me to believe its treating it as "0". {} should evaluate to true in keeping with standard javascript.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for completeness then we should also check null
and empty string
@jimmyhchan, @jairodemorais your thoughts? |
@vybs you did a great interpretation of the dust code, I think u are right, let's merge it after adding more tests! |
} | ||
context.stack.head['$idx'] = undefined; | ||
context.stack.head['$len'] = undefined; | ||
return chunk; | ||
} | ||
} else if (elem === true) { | ||
if (body) return body(this, context); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not do it by using the dust.isEmpty instead of len>0 that the exists section uses
dust.isEmpty = function(value) {
if (dust.isArray(value) && !value.length) return true;
if (value === 0) return false;
return (!value);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
--len is needed in the loop anyway. no need to call another function.--
nevermind. totally agree let's keep consistent and use isEmpty.. let's put it before the isArray check so that is checked first and for everything type.
FWIW the other clientside templating languages have this issue as well. Much debated. There seems to be some argument between what is correct and what is usable. The difference between {?foo} and {#foo} is useful handlebar added an each and an if helper to mustache that will render checks It seems we need to be very careful what we pick. |
@jimmyhchan on other note, I am curious how they do the if helper:) |
Ok i think i steered the conversation the wrong way. whatever boolean check we end up using, falsy sections should execute the else block... which this PR addresses. +1 on @vybs suggestion to use isEmpty. |
So reading through the plethora of bugs regarding what the correct truthy definitions should be, I think Dust does a good job in picking truthy values that make sense in templates. As pointed out earlier, everything in truthy except: when you refer to a key that doesn't exists... it is falsy because the value is undefined. |
we should update this in the wiki. except the 0 ( is treated as true ) BTW, is this line of code ever executed in the dust.isEmpty.
I could not see it covered int he code coverage. May be we dont have enough tests |
there is a |
unless i am missing something, the code says
|
Merging this PR, since we all agree we need this. |
Fixed :else in section when iterating over empty array.
So to confirm... the following: [{"key":0}] {?.key} should output b? I'm not getting that result personally... it's returning a for me. |
I tried the same on this tool: http://linkedin.github.com/dustjs/test/test.html I get b |
Okay, I'll carefully test and check before letting you know where I get. :) |
np ! does the tool output a for you> |
The library (not in the tool) appears to output the equivalent of "a", but what I'm actually working with is a bit more complex. Just going to work through a few test cases on my own stuff to try and either identify that I'm not having the problem or to narrow down the cause a little more. :) |
Okay. I'm pretty certain it's a problem. I've stripped down my code a lot to try to make it understandable. Using the tool with this for the template: {#cards}
{?.stars}
<div class="ratings r{.stars}"><span>{.stars} stars,</span> {.ratings} ratings</div>
{:else}
<div class="ratings r0"><span>no stars,</span> not enough ratings</div>
{/.stars}
{~n}
{/cards} And this for the JSON: {cards: [
{},
{ stars: 5, ratings: 5000 },
{ stars: 4, ratings: 4000 },
{ stars: 3, ratings: 3000 },
{ stars: 2, ratings: 2000 },
{ stars: 1, ratings: 1000 },
{ stars: 0, ratings: 10 },
{ ratings: 10 },
]} Both the last & second to last should output the same (correct?). But the second to last outputs "0 stars" (wrong) and the last outputs "no stars" which is correct. Maybe I'm missing something... not sure. Output I'm getting: <div class="ratings r0"><span>no stars,</span> not enough ratings</div>
<div class="ratings r5"><span>5 stars,</span> 5000 ratings</div>
<div class="ratings r4"><span>4 stars,</span> 4000 ratings</div>
<div class="ratings r3"><span>3 stars,</span> 3000 ratings</div>
<div class="ratings r2"><span>2 stars,</span> 2000 ratings</div>
<div class="ratings r1"><span>1 stars,</span> 1000 ratings</div>
<div class="ratings r0"><span>0 stars,</span> 10 ratings</div>
<div class="ratings r0"><span>no stars,</span> not enough ratings</div> |
In fact, I'm even getting "a" with the basic example: http://puu.sh/1fBc9 Using Safari on OS X btw. |
So the .key and .stars seem to be cause, its easy to see the exists section code in the dust.js and see how it evaluates them |
Kind of behaved the same in : http://akdubya.github.com/dustjs/ |
So are we confirming that this is an issue, or not? Both interpreters are giving me the same response. |
Please file a ticket on github, since this is closed. |
The "No friends :(" basic example from dust documentation was actually not working. Is anybody using this stuff?