Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing parent context in Meteor templates and template helpers

Tags:

meteor

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.

like image 565
cmal Avatar asked Dec 09 '12 17:12

cmal


2 Answers

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.

like image 62
opyh Avatar answered Oct 21 '22 04:10

opyh


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

like image 25
zorlak Avatar answered Oct 21 '22 04:10

zorlak