16

我在同一页面上的多个(任意多个)位置呈现相同的 Handlebars 模板。在每个模板中,我想要一个按钮来切换 div 的可见性。当我用 保存此状态时Session.set,单击一个按钮显然会切换所有不需要的模板实例中的所有 div。

我可以将状态保存在模板实例的数据上下文中(this.dataTemplate.myTemplate.renderedTemplate.myTemplate.created回调中绑定),但这有两个问题。

  1. this.data不是响应式数据源,因此不会传播到 div
  2. 我无权访问模板实例Template.myTemplate.events(如上讨论的meteor-core

最后,我可以以某种方式将其保存到集合中。但是我将如何唯一标识每个呈现的模板的状态?jQuery 也可能有一种 hacky 方式,但这不是我想要开发应该使用响应式模板的 Meteor 应用程序的方式。特别是当该模板变得更加复杂时。

我是否遗漏了一些东西,或者真的没有相当于 AngularJS 的控制器$scope为每个模板实例化传递一个?

更新:我在想这样的事情。

模板.html:

<template name="jsonObject">
    <input type="button" />
    <div class="{{hidden}}">content</div>
</template>

客户端.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;
    }
});
4

4 回答 4

18

所有其他答案都太复杂和/或过时了。从 Meteor 1.0 开始,维护每个模板状态的推荐解决方案是使用存储在模板实例中的反应变量

模板实例对象表示文档中模板的出现。它可以用于访问 DOM,并且可以为它分配在模板响应式更新时持续存在的属性。[...] 您可以为对象分配您选择的其他属性。

反应变量由reactive-var核心包提供:

一个 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>
于 2015-02-07T20:12:32.087 回答
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.Dependencytothis.datacreated

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

这有点涉及添加 to this.data,但它允许每个模板的反应性,当您依赖尚未保存到某个东西的数据时很有用Collection

于 2013-08-26T12:52:03.123 回答
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);
    };

以前的回答 我在我的项目中有同样的要求:唯一标识一个模板实例以使用 with 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 在每次模板渲染时都会更新,我没有找到其他方法。这意味着任何新的渲染都会使存储在 Session 中的唯一 id 无效。如果您的 div 包含响应式数据源,则会发生新的渲染。根据您的情况,这可能是一个问题,也可能不是。

于 2014-04-26T10:18:22.057 回答
0

我认为关于流星核心的讨论已经过时(尽管它是最近的)。根据文档(引用如下),这应该是可能的:

Template.myTemplate.events({
   foo: function(event, template) {
      var _div = template.find('...');
   }
});

处理程序函数接收两个参数:事件,一个包含有关事件信息的对象,以及模板,一个模板实例,用于定义处理程序的模板。处理程序还会在此接收一些额外的上下文数据,具体取决于处理事件的当前元素的上下文。在 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);
    }
});
于 2013-02-07T14:56:26.230 回答