-
Notifications
You must be signed in to change notification settings - Fork 73
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
Adding iterate helper #45
Conversation
As you no doubt know, this has been discussed off and on for a long time. As I see it the issues are:
Tactical concerns:
|
I think we need something like 'dustjs-extras', so that we can keep the core and default helpers in fair size. |
params = params || {}; | ||
var obj = params['on'] || context.current(); | ||
for (var k in obj) { | ||
chunk = chunk.render(bodies.block, context.push({key: k, value: obj[k]})); |
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.
Seems like this would need to be wrapped in a if (obj.hasOwnProperty(k))
check.
I am reading the comment from @akdubya and he says it very well. I miissed his explanation earlier. |
Here is the link where you can see akdubya's comment. He suggested a contextual helper rather than a built in solution. Here is the ref to see his comment: akdubya/dustjs#9 |
@rragan I read through the thread, and to be honest, I don't see what is the counter argument to supporting this. The response was basically "use a helper". This would make sense if it was something extremely esoteric, but a number of people requested it and it comes up again and again. It's a tiny bit of code. It makes the looping support consistent within dust and consistent with every other programming language. The only vaguely tangible push-back has been that the loop will have a non-deterministic order. But that's always true for looping over objects/hashes, and yet people do it all the same. |
BTW, one change worth considering is if we can support looping over objects and lists with the same JSON: {
"obj": {
"a": "b",
"c": "d",
"e": "f"
},
"list": [
"a",
"b",
"c"
]
} Dust:
Output:
|
@brikis98 It really does make sense to be part of the context. |
I agree having an object iterator in the context the same as how it works for lists makes sense. One case we should consider in the implementation and testing is nested iterations. For example: { "obj": { "a": "b", "c": "d", "list": ["a", "b", "c"] } } And then what something like this would output: {#obj key="key" value="value"} {key}: {value} {#list key="key" value="value"} {key}: {value} {/list} {/obj} |
I am not entirely against having an iterator helper, but I strongly On Thu, Jun 6, 2013 at 10:08 AM, sclatter notifications@github.com wrote:
|
Should we then make a explicit split between section/context and looping? We could leave the existing behavior, but then introduce a looping/iterating operator that works either on arrays or objects. From: Steven notifications@github.com I am not entirely against having an iterator helper, but I strongly On Thu, Jun 6, 2013 at 10:08 AM, sclatter notifications@github.com wrote:
|
I think the object-iterating use case is different enough that it should be On Thu, Jun 6, 2013 at 10:37 AM, sclatter notifications@github.com wrote:
|
@smfoote I'm not sure I understand your concern. While looping over an object, aren't you entering different levels into a context in exactly the same way? |
Objects and arrays are different in JavaScript and have different ways to iterate over them. The user should know which they have and express the iteration differently in dust. A separate helper takes care of that. Otherwise we have to start thinking about edge cases like what is the value of $idx and $len when an iteration is over an object instead of an array. |
Except libraries like jQuery and CoffeeScript provide a |
Talking about idx and len I think we need a good iterattion helper to deal with objects/arrays in one standard way. |
Maybe some checking is in order in terms of the tag. If I do something silly like {@iterate on=xxx/} things blow up in mysterious ways because there is no body. This should either be a meaningful error or the helper should quietly do nothing -- which kind of makes sense. |
The iteration helper above works on objects and arrays already and it works on strings. It all derives from how JavaScript for/in loops work on objects: http://javascriptweblog.wordpress.com/2011/01/04/exploring-javascript-for-in-loops/ {@iterate on=arr"} {key}:{value},{/iterate} when arr is [1,2,3,4] produces |
Perhaps we should consider a more enhanced iterate helper with an option to process they keys in sorted order. This would eliminate any browser dependence. I guess taking them in native order with no sort ought to be allowed but with appropriate educational documentation/warnings as there are legitimate use cases. |
Since I just had to solve arbitrary nested iteration of an object (assuming an iter helper), I thought I'd share it here in case anyone needs it: First a not completely general solution. It shows how to descend levels in a structured object provided you know the keys which represents your sub-object of interest. Realistically, you may want to format different parts of your object differently so separate partials for various sub-parts seems plausible. {@iter key=obj} “child” partial to handle child level Data model: If you are looking for a fully general solution to handle sub-objects with no prior knowledge of their key name (e.g, maybe writing some sort of hierarchical object dumper), here is a solution. It feels a bit hacky as it depends on object.toString yielding [object Object] but this is part of the standard so it should be valid and portable. child partial: Invocation on object from the data model: |
Had some more thoughts on this over the weekend and played around with a new version. It has an optional sort parameter. If you specify sort="" you get the default JS sort. If you specify sort="name", then context.global is checked for a function with that name which should implement what compare you desire. Adding sort provides a browser-independent version of iteration so a user is assured of the same answers. I left the no sort version around if it happens to meet your needs as it would be faster. I also added "type" to the key and values pushed to the stack. This makes it cleaner to handle nested objects when you want to do something different for one of the substructures. Note the change from chunk.render to bodies.block. Since chunk.render just calls body(chunk, context) this ought to be marginally faster.
Thoughts? |
@rragan I like it. It seems fairly clean and quite useful, both for the simple case (I don't care about order) and the more complicated ones. Only two questions I would have are:
|
I agree that the names should be $key, $value, $type to stay out of the way of user names and in the pattern of $idx. Compare functions are easy to define, viz. As written, using sort="" gives you the default JavaScript sort order which is ascending. I guess it boils down to whether we supply a default choice for a descending sort. I guess sort="asc" and sort="desc" could be "built-in" options if it was thought useful enough. |
Do you think assuming current context " |
I'm inclined to omit it particularly since setting context to an object via {#obj} is generally not useful -- part of the muddy waters around dual use of {#xxx} for iteration and context setting. |
Here is an updated version supporting ascending and descending sorts built-in and changed to use $key, $value, $type names. Helper name is up for grabs. Some have used iter while I'm sure those favoring readability over a few key strokes will prefer "iterate".
|
Looks pretty good to me. Naming is, of course, the most difficult part :) Other alternatives to consider are |
how about iterate ? :) |
iterate it is unless others feel differently. forEach seems a bit wrong as it really is a for..in loop. Loop seems a bit to general and inviting expectations beyond what it does. |
iterate for me too. |
Works for me. |
Submitted alternate pull request #49 in the style discussed here along with tests. They are pretty similar at this point except for a bunch of tests in the other PR to test all the use cases and error cases. Good joint work from all to refine this. |
This has lingered long enough. I am assuming there is little sentiment for putting this in the main dustjs-helpers. I have captured the implementation in a separate repo at https://github.com/rragan/dust-motes/tree/master/src/helpers/control/iterate and it is available as an npm module: require('dustmotes-iterate') Having worked hand-in-hand with the original contributor, I will leave the final decision to accept this PR or close it to someone else. There is now an alternative though. |
Adding iterate helper, to iterate over object and get any key|value storage blindly.
rashad612/dustjs-helpers@9039130