【问题标题】:Making a template helper reactive in Meteor在 Meteor 中使模板助手反应
【发布时间】:2014-06-20 08:49:45
【问题描述】:

我正在构建一个聊天应用程序,在我的“新聊天”页面上,我有一个联系人列表,您可以通过点击它们来一一选择(在此基础上,我应用了一个 CSS 选择的类并将用户 ID 推送到名为“newChatters”的数组。

我想让这个数组可用于辅助方法,这样我就可以显示一个反应式名称列表,其中包含已添加到聊天中的所有用户。

我想在其中显示响应式列表的模板:

<template name="newChatDetails">
  <div class="contactHeader">
    <h2 class="newChatHeader">{{newChatters}}</h2>
  </div>
</template>

选择联系人时触发的点击contactItem事件:

Template.contactsLayout.events({
 'click #contactItem': function (e) {
   e.preventDefault();
   $(e.target).toggleClass('selected');
   newChatters.push(this.username);
...

newChatters 数组正在正确更新,因此到目前为止一切正常。现在我需要让 {{newChatters}} 响应式更新。这是我尝试过的方法,但它不正确并且不起作用:

Template.newChatDetails.helpers({
  newChatters: function() {
    return newChatters;
  }
});

如何以及在哪里使用 Deps.autorun() 来完成这项工作?我什至需要它,因为我认为辅助方法会在失效时自动更新?

【问题讨论】:

    标签: javascript meteor


    【解决方案1】:

    1) 在定义对象的相同位置定义Tracker.Dependency:

    var newChatters = [];
    var newChattersDep = new Tracker.Dependency();
    

    2) 在读取对象之前使用depend():

    Template.newChatDetails.newChatters = function() {
      newChattersDep.depend();
      return newChatters;
    };
    

    3) 写完后使用changed():

    Template.contactsLayout.events({
      'click #contactItem': function(e, t) {
        ...
        newChatters.push(...);
        newChattersDep.changed();
      },
    });
    

    【讨论】:

    • 您刚刚缓解了数小时的挫败感。谢谢莱克宁!
    【解决方案2】:

    您应该为此使用Session 对象。

    Template.contactsLayout.events({
     'click #contactItem': function (e) {
       //...
       newChatters.push(this.username);
       Session.set('newChatters', newChatters);
     }
    });
    

    然后

    Template.newChatDetails.helpers({
      newChatters: function() {
        return Session.get('newChatters');
      }
    });
    

    【讨论】:

      【解决方案3】:

      您可以使用本地 Meteor.Collection 光标作为响应式数据源:

      var NewChatters = new Meteor.Collection("null");
      

      模板:

      <template name="newChatDetails">
        <ul>
          {{#each newChatters}}
            <li>{{username}}</li>
          {{/each}}
        </ul>
      </template>
      

      事件:

      Template.contactsLayout.events({
        'click #contactItem': function (e) {
          NewChatters.insert({username: this.username});
        }
      });
      

      助手:

      Template.newChatDetails.helpers({
        newChatters: function() { return NewChatters.find(); }
      });
      

      【讨论】:

      • 没想到这一点。我将在下面的另一个答案中使用会话对象,但这是另一种有用的方法,谢谢
      • var NewChatters = new Meteor.Collection(null);如果您将 null 放在引号中,它只会将您的集合命名为“null”并且仍然与服务器同步。
      【解决方案4】:

      要模仿Session 的行为而不污染Session,请使用ReactiveVar:

       Template.contactsLayout.created = function() {
            this.data.newChatters = new ReactiveVar([]);
       }
      
       Template.contactsLayout.events({
            'click #contactItem': function (event, template) {
                  ...
                  template.data.newChatters.set(
                      template.data.newChatters.get().push(this.username)
                  );
                 ...
      

      然后,在内部模板中,使用父响应式数据源:

       Template.newChatDetails.helpers({
            newChatters: function() {
                 return Template.parentData(1).newChatters.get();
            }
       });
      

      【讨论】:

      • 我认为这是最好的答案。然而,一个建议可能是将反应 var 移到模板数据对象之外,并简单地移到模板实例本身中。这样可以保持数据对象整洁。
      • @Adam 不,你不能从data 对象中取出它,因为这正是允许你从模板访问父数据的技巧:使用parentData 方法。
      • 不是原生的,反正...stackoverflow.com/questions/27949407/…
      【解决方案5】:

      对于在 2015 年及以上寻找解决方法的人(因为帖子是 2014 年的)。

      我正在实现一个帖子向导 pw_module,我需要根据 路由参数 反应性地更新数据:

      Router.route('/new-post/:pw_module', function(){
          var pwModule = this.params.pw_module;
          this.render('post_new', {
              data: function(){
                  switch (true) {
                      case (pwModule == 'basic-info'):
                          return {
                              title: 'Basic info'
                          };
                          break;
                      case (pwModule == 'itinerary'):
                          return {
                              title: 'Itinerary'
                          };
                          break;
                      default:
                  }
              }
          });
      }, {
          name: 'post.new'
      });
      

      稍后在模板中做一个:

      &lt;h1&gt;{{title}}&lt;/h1&gt;

      改变路线

      更新 URL 的导航如下所示:

      <nav>
          <a href="{{pathFor route='post.new' pw_module='basic-info'}}">Basic info</a>
          <a href="{{pathFor route='post.new' pw_module='itinerary'}}">Itinerary</a>
      </nav>
      

      希望它仍然可以帮助某人。

      【讨论】:

        猜你喜欢
        • 2013-06-19
        • 2015-01-06
        • 1970-01-01
        • 1970-01-01
        • 2015-09-20
        • 1970-01-01
        • 2015-07-28
        • 2015-10-13
        • 2014-04-04
        相关资源
        最近更新 更多