Meteor #each loop ready

时间:2015-05-26 02:50:34

标签: javascript meteor meteor-blaze

我想知道是否有任何方法可以知道#each循环是否已准备好"。通过"准备好"我的意思是它渲染了所有节点并插入到DOM中。我甚至不会谈论onRendered回调(旧rendered)。我试过了

<template name="myTemplate">
<div class="some-class">
    {{#if Template.subscriptionsReady}}
       {{#each messages}}
          <div>{{text}}</div>
       {{/each}}
       <script>
           $(".some-class").trigger("LOOP_READY")
       </script>
    {{/if}}
</div>
</template>


Template.myTemplate.onRendered(function(){
    this.$(".some-class").on("LOOP_READY", doSomething)
})

但它也不起作用。我不想使用计时器。

更新

messages是当前对话框的文本消息集合,dialogId是存储在Session中的被动变量。

Template.myTemplate.onCreated(function(){
    var self = this;
    self.autorun(function(){
        self.subscribe("messages", Session.get("dialogId"))
    })
})

因此,如果有人更改了dialogId,myTemplate将加载另一个对话框消息,我想知道这些消息何时准备就绪,以滚动到特定消息。简单的onReady不起作用,因为在渲染所有消息并获得自己的高度之前,我无法准确地调用scrollTop。

2 个答案:

答案 0 :(得分:1)

当一个Spacebars {{#each}}块已经完成了对其跨越的每个项目的DOM渲染时,没有简单的方法可以获得通知。

最佳解决方案是使用另一个反应计算(Tracker.autorun)来观察您的消息游标更改。

每当您的消息列表被修改时,您可以使用Tracker.afterFlush在执行任何其他工作后执行任意代码后运行任意代码。

{{#each}}块是其中一个计算,其作用是侦听您作为参数提供的反应数据源并将其Template.contentBlock重新呈现为从正在迭代的源中获取的项目的次数结束,将当前项目作为当前数据上下文。

通过监听与{{#each}}块帮助程序完全相同的反应数据源并在完成自己的反应计算后运行代码,您可以获得实际请求的行为而不依赖于某些奇怪的{{1} }技巧。

以下是此模式的完整实现:​​

HTML

setTimeout

JS

<template name="myTemplate">
  <div class="some-class">
    {{#if Template.subscriptionsReady}}
      {{#each messages}}
        <div class="message">{{text}}</div>
      {{/each}}
    {{/if}}
  </div>
</template>

答案 1 :(得分:1)

@saimeunt提供了优雅的解决方案,但我以其他方式实现了它,也许有人发现它也很有帮助。

由于我不希望每次新消息到达时我的代码都被执行,因此在自动运行完成后我无法触发滚动。 (你会说,好的,在仅依赖dialogId的自动运行中执行。 - 然后我无法获得此对话框的确切消息计数,因为订阅需要一些时间)

HTML

<template name="myTemplate">
  <div class="chat">
    {{#if Template.subscriptionsReady}}
      <div class="messages">
          {{#each messages}}
            <div class="message">{{text}}</div>
          {{/each}}
      </div>
      <script>$(".chat").trigger("MESSAGES_READY_EVENT")</script>
    {{/if}}
  </div>
</template>

JS

Template.chat.onCreated(function () {
    var self = this;
    self.messages = function() {
        return Messages.find({dialogId:Session.get("dialogId")})
    }
    self.autorun(function(){
        self.subscribe("messages", Session.get("dialogId"));
    })
});
//helpers skipped
Template.chat.onRendered(function () {
    var self = this;
    self.$(".chat").on("MESSAGES_READY_EVENT", function () {
        var computationNumber = 0;
        var $messages = self.$(".messages");
        //how many massages we have to render
        var total = self.messages().count();
        //max tries
        var maxTries = 10;
        var intervalId = Meteor.setInterval(function () {
            var totalNodes = $messages.children().length;
            if (computationNumber++ >= maxTries || total <= totalNodes) {
                Meteor.clearInterval(intervalId);
                $messages.scrollTop(someValue);
            }
        }, 100);
    });
});