在Meteor模板和模板助手中访问父上下文

我遇到了一个模板上下文的情况,我很难find解决的办法。

这里是问题的模板:

{{#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}} 

这是一个投票文件的例子:

 { _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 } ] } 

这是问题

当模板落入参与者的#each中时,不再有权访问vote上下文,因此无法访问每个投票的可用选项。

我可以通过使用../options handlebarspath来跳回到父上下文,但是这不会影响模板助手的上下文,所以在Template.vote.is_selected_option引用了当前的participant ,不是目前的voteoption ,也无法知道我们目前正在迭代的option

任何build议如何解决这个问题,而不诉诸DOM操作和jQuery shenanigans?

这是一个模板问题,已经出现了多次。 我们需要在模板,模板助手和模板事件中达成模板上下文层次结构的正式方法。

这不是特别漂亮,但我做了这样的事情:

 <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; }); } }); 

这与AVGPbuild议的方法类似,但是在辅助级而不是db级上增加了数据,我认为这有点轻。

如果你喜欢,你可以尝试写一个Handlebars块帮手eachWithParent ,将抽象这个function。 meteor的把手扩展logging在这里: https : //github.com/meteor/meteor/wiki/Handlebars

从Spacebars(Meteor的新模板引擎)看来,您可以使用../来访问{{#each}}块内的父上下文。

在Meteor 0.9.1中,您也可以编写一个帮助程序,并在其实现中使用Template.parentData()

我不知道正式的方法(如果有的话),但是为了解决你的问题,我会把参与者与父母的ID连接起来,像这样:

 { _id: "1234", question: "Whats up?", ... participants: [ { _id: "abcd", parent_id: "1234", vote: 0 } ] } 

并在助手,事件等使用这个parent_id跳回到父母使用findOne。 这显然是一个次优的事情,但只要没有办法引用父上下文,这是最简单的方法。 也许有一种方法,但是如果没有在文档中提到的话,它就很好地隐藏在meteor的内部工作中,如果是这样的话:请更新这个问题,如果你find一个。

这是一个远投,但也许这可以工作:

 {{#with ../}} {{#each options}} {{this}} {{/each}} {{/with}} 

这应该让生活更轻松。

 // use #eachWithParent instead of #each and the parent._id will be passed into the context as parent. Handlebars.registerHelper('eachWithParent', function(context, options) { var self = this; var contextWithParent = _.map(context,function(p) { p.parent = self._id; return p; }); var ret = ""; for(var i=0, j=contextWithParent.length; i<j; i++) { ret = ret + options.fn( contextWithParent[i] ); } return ret; }); 

继续前进,改变

 p.parent = self._id; 

任何你想要在父上下文访问。

修复:

 // https://github.com/meteor/handlebars.js/blob/master/lib/handlebars/base.js // use #eachWithParent instead of #each and the parent._id will be passed into the context as parent. Handlebars.registerHelper('eachWithParent', function(context, options) { var self = this; var contextWithParent = _.map(context,function(p) { p.parent = self._id; return p; }); return Handlebars._default_helpers.each(contextWithParent, options); }); 

这工作:)没有错误

只需注册一个全球模板帮手:

 Template.registerHelper('parentData', function () { return Template.parentData(1); } ); 

并在您的HTML模板中使用它:

 {{#each someRecords}} {{parentData.someValue}} {{/each}} 

=======编辑

对于meteor1.2+,你推荐使用:

 UI.registerHelper('parentData', function() { return Template.parentData(1); }); 

我被困在一个类似的方式,发现其他答案中build议的Template.parentData()方法目前不能在事件处理程序内工作(请参阅https://github.com/meteor/meteor/issues/5491 )。 用户Lirbank发布了这个简单的解决方法:

将数据从外部上下文传递到内部上下文中的html元素,使用相同的模板:

 {{#each companies}} {{#each employees}} <a href="" companyId="{{../id}}">Do something</a> {{/each}} {{/each}} 

现在公司ID可以通过类似于事件处理程序的方式进行访问

 $(event.currentTarget).attr('companyId') 
 "click .selected":function(e){ var parent_id = $(e.currentTarget).parent().attr("uid"); return parent_id }, 
 <td id="" class="staff_docs" uid="{{_id}}"> {{#each all_req_doc}} <div class="icheckbox selected "></div> {{/each}} </td> 

{{#each parent}}

{{#each child}}

<input type="hidden" name="child_id" value="{{_id}}" />

<input type="hidden" name="parent_id" value="{{../_id}}" />

{{/each}}

{{/each}}

_id不是事物的_did,而是父代的ID。