I'm running into a template context situation that I'm having a hard time finding a way around.
Here's the template in question:
{{#each votes}} <h3>{{question}}</h3> <ul> {{#each participants}} <li> <p>{{email}}</p> <select name="option-select"> {{#each ../options}} <option value="{{option}}" class="{{is_selected_option}}">{{option}}</option> {{/each}} </select> </li> {{/each}} </ul> </div> {{/each}}
And here's an example of a vote document:
{ _id: '32093ufsdj90j234', question: 'What is the best food of all time?' options: [ 'Pizza', 'Tacos', 'Salad', 'Thai' ], participants: [ { id: '2f537a74-3ce0-47b3-80fc-97a4189b2c15' vote: 0 }, { id: '8bffafa7-8736-4c4b-968e-82900b82c266' vote: 1 } ] }
And here's the issue...
When the template drops into the #each
for participants, it no longer has access to the vote
context, and therefore doesn't have access to the available options for each vote.
I can somewhat get around this by using the ../options
handlebars path to jump back into the parent context, but this doesn't affect the context of the template helper, so this
in Template.vote.is_selected_option
refers to the current participant
, not to the current vote
or option
, and has no way of knowing which option
we are currently iterating through.
Any suggestions on how to get around this, without resorting to DOM manipulation and jQuery shenanigans?
This is a templating issue that has come up multiple times for me. We need a formal way of reaching up the template context hierarchy, in templates, template helpers, and template events.
It seems since Spacebars (Meteor's new template engine), you have access to the parent context within {{#each}}
blocks using ../
.
In Meteor 0.9.1, you can also write a helper and use Template.parentData()
in its implementation.
It's not particularly pretty, but I've done something like this:
<template name='forLoop'> {{#each augmentedParticipants}} {{> participant }} {{/each}} </template> <template name='participant'> ... Question: {{this.parent.question}} ... </template> // and in the js: Template.forLoop.helpers({ augmentedParticipants: function() { var self = this; return _.map(self.participants,function(p) { p.parent = self; return p; }); } });
It's similar to the approach that AVGP suggested, but augments the data at the helper level instead of the db level, which I think is a little lighter-weight.
If you get fancy, you could try to write a Handlebars block helper eachWithParent
that would abstract this functionality. Meteor's extensions to handlebars are documented here: https://github.com/meteor/meteor/wiki/Handlebars
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With