Jun '16
Each and With There are also two Spacebars built-in helpers, {{#each}}, and {{#with}}, which we do not recommend using (see use each-in below). These block helpers change the data context within a template, which can be difficult to reason about.
How about this case? (we care about <ul>
):
+with games
ul
+each game in this
li {{game.name}}
else
| Not Found
or we have strange code without {{#with}}
+let tmp_games=games
+if tmp_games
ul
+each game in tmp_games
li {{game.name}}
else
| Not Found
Jun '16
One Blaze pattern that I am very fond of is ditching helpers and storing everything on the template instance. In onCreated:
Template.templateName.onCreated(function() {
let tpl = this;
_.extend(tpl, {
someState: new ReactiveVar([], EJSON.equals),
initialize(params) {
// do whatever initialization e.g.:
tpl.listenForChanges();
},
listenForChanges() {
tpl.autorun(comp => ...);
},
useThisInsteadOfHelper(arg1, arg2) {
},
}).initialize(tpl.data);
});
Then if you declare a global helper:
Template.registerHelper('$tpl', function () {
return Template.instance();
});
You can do {{$tpl.useThisInsteadOfHelper arg1 arg2}}
or {{$tpl.someState.get}}
inside of the templateName
html file. This means that your functions can call each other, store state on the template instance without calling Template.instance()
everywhere, and aren’t run everytime anything in the data context changes (if you want the function to rerun whenever anything in the data context changes you have to explicitly call Template.currentData()
). This gives waaaay more flexibility.
1 reply
Jun '16
I have elegant bicycle for store state:
You have clicked the button {{state.counter}} times.
<button>click</button>
Template2 'hello',
states: counter: 0
events: 'click button': ->
# increment the counter when button is clicked
@state.counter += 1
Jun '16
You still need {{#with ... }}
to switch the context to the looped item for accessing it from an event and don’t want to write another template for it:
{{#each user in users}}
{{ user.name }}
{{#with user=user }}
<span class="remove">X</span>
{{/with}}
{{/each}}
Template.users.events({
'click .remove': function(event) {
console.log(this);
}
});
Using the {{#with }}
wrapper console.log will return {user: {name: ... }}
; without it it will return {users: [{name: ...}]}
and you won’t know which user from the list you clicked on.
Is there a way to add the user to the context with {{#let }}
instead? The other way I found to do it is add a data attribute to the span an retrieve it from the event.target.dataset
but then it turns into a string and feels wrong. Sometimes I still need access to other objects from the outer context and then it turns into a monstrous {{#with user=user users=users foo=foo }}
.
1 reply
Jun '16
Thanks! It is better. But we need define new variable:
+with tmp_games=games
ul
+each game in tmp_games
li {{game.name}}
else
| Not Found
Because helper games
called twice in this case:
+with games=games
ul
+each game in games
li {{game.name}}
else
| Not Found