我在同一页面上的多个(任意多个)位置渲染相同的Handlebars模板。在每个模板中,我想要一个按钮来切换div的可见性。当我使用Session.set
保存此状态时,单击一个按钮显然会切换所有模板实例中不需要的所有div。
我可以将状态保存在模板实例的数据上下文中(在this.data
和Template.myTemplate.rendered
回调中绑定到Template.myTemplate.created
),但是有两个问题。
this.data
不是反应式数据源,因此不会传播到div Template.myTemplate.events
中的模板实例(如meteor-core所述)最后,我可以以某种方式将其保存到一个集合中。但是,我如何唯一地标识每个呈现的模板的状态? jQuery可能也有一种hacky方式,但这不是我想要开发应该与反应模板一起使用的Meteor应用程序的方式。特别是,当该模板变得更复杂时。
我是否遗漏了某些东西,或者是否真的没有等同于AngularJS的控制器,每个模板实例化都会传递$scope
?
更新: 我在考虑这样的事情。
template.html:
<template name="jsonObject">
<input type="button" />
<div class="{{hidden}}">content</div>
</template>
client.js:
Template.jsonObject.hidden = function(){
var ret = "";
if (this._hidden) {
ret = "hidden";
}
return ret;
};
Template.jsonObject.events({
'click input' : function(event, template){
template.data._hidden = true;
}
});
答案 0 :(得分:18)
所有其他答案都过于复杂和/或过时。从Meteor 1.0开始,维护每个模板状态的建议解决方案是使用存储在reactive variables中的template instance:
模板实例对象表示文档中出现的模板。它可以用于访问DOM,并且可以为其分配属性,这些属性在模板被反应更新时持久存在。 [...]您可以将您选择的其他属性分配给对象。
活跃变量由reactive-var
core package提供:
ReactiveVar包含可以获取和设置的单个值,因此根据通常的响应数据源合约,调用
set
将使任何调用get
的计算无效。
您的代码变为:
Template.jsonObject.onCreated = function () {
this.hidden = new ReactiveVar(false);
};
Template.jsonObject.helpers({
hidden: function () {
return Template.instance().hidden.get() ? 'hidden' : '';
}
});
Template.jsonObject.events({
'click input': function (event, template) {
template.hidden.set(true);
}
});
HTML与您期望的相同:
<template name="jsonObject">
<button>Click Me</button>
<p>Hidden is {{hidden}}.</p>
</template>
答案 1 :(得分:2)
这就是我实现每个模板实例反应源的方法
我只想询问用户灭绝状态灭绝时恐龙灭绝的原因。
<template name="dinosaur">
<label for="extinction-status">Extinction status</label>
<select name="extinction-status">
<option value="not-extinct">Not extinct</option>
<option value="extinct">Extinct</option>
</select>
{{#if isExtinct extinctStatus newExtinctStatus extinctStatusDep}}
<label for="extinction-reason">Reason for extinction</label>
<input name="extinction-reason" type="text" placeholder="Why is it extinct?"/>
{{/if}}
</template>
要反复显示原因字段,我们会在模板Deps.Dependency
函数中添加this.data
到created
Template.dinosaur.created = function() {
this.data.newExtinctStatus = null;
this.data.extinctStatusDep = new Deps.Dependency;
};
我们会倾听用户何时更改消退状态选择,并更新newExtinctStatus
上的changed
并呼叫extinctStatusDep
。
Template.dinosaur.events({
'change [name="extinction-status"]': function(event, template) {
var extinctStatus = $(event.target).val();
template.data.newExtinctStatus = extinctStatus;
template.data.extinctStatusDep.changed();
}
});
在助手中,我们说我们依赖于传递的Deps.Dependency
Template.dinosaur.helpers({
isExtinct: function(status, newStatus, statusDep) {
if (statusDep) {
statusDep.depend();
}
if (newStatus) {
if (newStatus == 'extinct') {
return true;
}
else if (status == 'extinct') {
// No new status is set, so use the original.
return true;
}
}
});
这是一个涉及添加到this.data
的黑客攻击,但它允许每个模板的反应性,当您依赖尚未保存到Collection
中的某些内容的数据时非常有用
答案 2 :(得分:1)
更新的答案 - METEOR 0.8.3
Meteor现在提供UI._templateInstance()
功能,可以访问模板助手中的模板实例。这样可以实现更清晰的实施:
1。
在下面的HTML代码中,删除{{#with templateInstanceId=getTemplateInstanceId}}
2。 用这个替换JS代码:
var templateInstanceId = 0;
Template.divWithToggleButton.created= function()
{
this.templateInstanceId = ++templateInstanceId;
};
Template.divWithToggleButton.events(
{
'click button': function(event, template)
{
Session.set("visible", template.templateInstanceId);
},
});
Template.divWithToggleButton.visible= function()
{
return Session.equals("visible", UI._templateInstance().templateInstanceId);
};
前回答
我的项目中有相同的要求:唯一标识要与Session.set
一起使用的模板实例。
这是我的简单黑客,使用上下文替换和'滑动'唯一实例ID(稍后会详细介绍):
客户端代码中的任何位置,放置:
var templateInstanceId = 0;
UI.registerHelper('getTemplateInstanceId', function()
{
return templateInstanceId++;
});
然后在要唯一标识实例的模板中使用{{#with templateInstanceId=getTemplateInstanceId }}
。在你的例子中,它可能是这样的(未经测试):
HTML:
<!-- Div with a toggle visibility button. Use as a Block Helpers (with # instead of >) -->
<template name="divWithToggleButton">
{{#with templateInstanceId=getTemplateInstanceId }}
<div>
<!-- The 'toggle visibility' button -->
<button type="button">Toggle Visibility</button>
<!-- The div content -->
{{#if visible}}
{{> UI.contentBlock}}
{{/if}}
</div>
{{/with}}
</template>
JS(客户代码):
Template.divWithToggleButton.events(
{
'click button': function(event, template)
{
Session.set("visible", this.templateInstanceId);
},
});
Template.divWithToggleButton.visible= function()
{
return Session.equals("visible", this.templateInstanceId);
};
现在关于这个奇怪的'滑动'唯一实例id:
此ID在每个模板渲染时更新,我找不到其他方法。 这意味着任何新呈现都将使会话中存储的唯一ID无效。如果您的div包含反应数据源,则会发生新的渲染。根据您的情况,这可能是一个问题。
答案 3 :(得分:0)
我认为关于meteor-core的讨论已经过时(虽然它是最近的)。 Per the docs(引自下文),这应该是可能的:
Template.myTemplate.events({
foo: function(event, template) {
var _div = template.find('...');
}
});
处理程序函数接收两个参数:event,包含事件信息的对象,以及模板,定义处理程序的模板的模板实例。处理程序还会在此处接收一些其他上下文数据,具体取决于处理事件的当前元素的上下文。在Handlebars模板中,元素的上下文是发生该元素的Handlebars数据上下文,它由块帮助程序(如#with和#each)设置。
<强>更新强>
假设每个可隐藏的div都有一个唯一的id,如果你尝试过类似的东西怎么办?我还没有测试过。
Template.jsonObject.hidden = function(){
var _id = $(".classOfPossibleHiddenDiv").prop("id");
return Session.get(_id) || false;
};
Template.jsonObject.events({
'click input' : function(event, template){
Session.set($(template.find(".classOfPossibleHiddenDiv")).prop("id"), true);
}
});