在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
,不是目前的vote
或option
,也无法知道我们目前正在迭代的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。