This question is about using the dust.js templating system with paths to data in sub-contexts. My intention is to support i18n using a map of keys to strings.
Given data like this:
{i18n : { firstname : "First Name" },
people : [
{"name" : "Moe"},
{"name" : "Curly"}
]}
In dust you can use sections to list each person:
{#people}
{name}
{/people}
And you can use a path to get access to the firstname i18n string:
{i18n.firstname}
But the following does not work:
{#people}
{i18n.firstname}: {name}
{/people}
In fact, the documentation specifically says:
To avoid brittle and confusing references, paths never backtrack up the context stack. If you need to drill into a key available within the parent context, pass the key as a parameter.
So I try and pass the key as a parameter:
{#people i18n=i18n}
{i18n.firstname}: {name}
{/people}
But this doesn't work. When I experiment with this on the dust homepage, I see the piled template has this code:
"i18n": ctx.get("i18n")
Which makes me think the above example should work fine.
So what gives? How can I make this work?
Note: The following does work:
{#people firstname=i18n.firstname}
{firstname}: {name}
{/people}
But this doesn't work well if you need to access a lot of i18n keys within the people context.
This question is about using the dust.js templating system with paths to data in sub-contexts. My intention is to support i18n using a map of keys to strings.
Given data like this:
{i18n : { firstname : "First Name" },
people : [
{"name" : "Moe"},
{"name" : "Curly"}
]}
In dust you can use sections to list each person:
{#people}
{name}
{/people}
And you can use a path to get access to the firstname i18n string:
{i18n.firstname}
But the following does not work:
{#people}
{i18n.firstname}: {name}
{/people}
In fact, the documentation specifically says:
To avoid brittle and confusing references, paths never backtrack up the context stack. If you need to drill into a key available within the parent context, pass the key as a parameter.
So I try and pass the key as a parameter:
{#people i18n=i18n}
{i18n.firstname}: {name}
{/people}
But this doesn't work. When I experiment with this on the dust homepage, I see the piled template has this code:
"i18n": ctx.get("i18n")
Which makes me think the above example should work fine.
So what gives? How can I make this work?
Note: The following does work:
{#people firstname=i18n.firstname}
{firstname}: {name}
{/people}
But this doesn't work well if you need to access a lot of i18n keys within the people context.
Share Improve this question edited Aug 7, 2012 at 21:08 JBCP asked Aug 7, 2012 at 18:12 JBCPJBCP 13.5k9 gold badges75 silver badges112 bronze badges 1- I also opened a ticket on the LinkedIn GitHub which has a detailed discussion of this: github./linkedin/dustjs/issues/100#issuement-7615536 – JBCP Commented Aug 9, 2012 at 16:25
2 Answers
Reset to default 5Paths can be used in keys and in sections to specify where you want Dust to look for keys. To understand how and when to use paths, you should first understand how Dust looks for keys when there are no paths. You might want to sit down.
When searching for keys, Dust first looks in the current context, then looks in each parent context until there are no more parents to search in. If no key is found, Dust does nothing (unless you are using an Exists or Not Exists Section). If Dust finds the key, it stops searching and uses the given value. That's not too foreign, right? That's how JavaScript looks for variables in execution environments.
However, instead of looking up the tree toward root, when a path is used, Dust only looks at children. This is best illustrated with an example.
JSON:
{
"i18n": {
"firstname": "First Name"
},
"name": "My Dust Template",
"firstname": "Surprise!",
"people": [
{
"name": {
"firstname": "Moe",
"lastname": "Howard"
}
},
{
"name": {
"firstname": "Curly",
"lastname": "Howard"
}
}
]
}
And the Dust:
Dust Template:
{! Show the name of the template !}
{name}{~n}
{#people}
{!
As you noted, the following will not work, because
when using a path, Dust only searches
deeper into the JSON. The output will be:
": Surprise!"
!}
{i18n.firstname}: {firstname}{~n}
{!
To get your i18n string, you need to look up the
stack instead of down. This can be done by using a
section without a path, as follows. The output will be:
"First Name: Moe"
"First Name: Curly"
!}
{#i18n}{firstname}{/i18n}: {name.firstname}{~n}
{!
Note that we successfully used the path to
get the firstname of each of the people.
!}
{/people}
[EDIT]: For more info, check out this wiki page from the LinkedIn fork of Dust: https://github./linkedin/dustjs/wiki/Where-else-does-Dust-search-if-the-value-is-not-defined%3F-A.K.A.-Dust-Scoping
if this is your template:
{#people i18n=i18n}
{i18n.firstname}: {name}
{/people}
here's how your context stack looks like as it iterates through your 'name' array
{ your original context}
i18n -> firstname: "First Name"
name -> "Moe"
what happens is, when you define a parameter, dust pushes into the context stack all the parameters you defined. then when it finds an array in your context, dust pushes into the stack, one at a time, all the items in the array.
so now when you define a path context within the section, even though you've passed i18n in as a parameter, the i18n context is still up in the context stack, and when you try to access i18n with a path, like {i18n.firstname}, dust wouldn't find it, coz it has to backtrack to find it, and getPath doesn't do backtracks. the get method, on the other hand does backtrack, so that's why, when you do this:
{#people firstname=i18n.firstname}
{firstname}: {name}
{/people}
it works, because it's accessing the firstname within the section with a get method. hope you understand what i'm trying to say.
what i'd do is define a helper method that takes in a section like so:
{#people}
{#i18n}{firstname}{/i18n}: {name}{~n}
{/people}
and define the method in your context (or push it to your global context [defined with makeBase] to make it a global helper) like so:
i18n: function(chunk, context, bodies, params){
var trans = context.get(translation); //or whatever name you give to your i18n list
chunk.render(bodies.block, context.push(trans));
return chunk;
}
tested this on the dust website and it works. the advantage to this approach is you can now format your i18n output within the confines of the section. also, it would be good to define both the helper and the i18n list in your global context, so do use makeBase for that. all the best.