2015-05-26 68 views
2

我想知道是否有任何方法可以知道#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) 
}) 

但它也不管用。我不想使用計時器。

UPDATE

messages是文字信息的集合,用於當前對話,dialogId是存儲在Session反應變種。

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

因此,如果有人改變dialogId,MyTemplate的加載另一個對話框中的消息,我想知道這個消息是準備好了,滾動到一個特定的消息。簡單的onReady不起作用,因爲在所有消息被渲染並獲得它自己的高度之前,我無法準確地調用scrollTop。

+0

你確定'用'waitOn一起onRendered' '(看鐵路路由器)或類似的不工作?我可以想象,您看到的觸發器是從模板第一次渲染時開始的,即沒有數據可用時。我懷疑你希望只有當數據到達並且所有'每個'都已經渲染時纔會觸發它。你是否在等待數據? –

+0

@ZuzEL你能解釋你爲什麼要這樣嗎?你需要初始化一個插件什麼的? –

+0

我想,如果我得到你想要的,那麼你的scrollToTop在添加新元素之前就開始了。所以從技術上講,如果你只是在setTimeout(func,0)中調用scrollToTop,那麼當你調用scroll時會更新元素的高度。 –

回答

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

有當Spacebars {{#each}}塊做渲染到DOM中每一個項目的跨越,以獲得通知沒有簡單的方法。

最好的解決方案是使用另一個反應式計算(Tracker.autorun)來觀察您的消息光標更改。

每當您的郵件列表被修改,所有其他無功計算完成後執行任何他們的工作後,你可以運行任意代碼,使用Tracker.afterFlush

{{#each}}塊是這些計算之一,它的作用是監聽作爲參數的反應性數據源並將其當前值作爲參數從源迭代獲取項目的次數爲當前數據上下文。

通過聽取完全相同的反應數據源作爲{{#each}}塊助手和運行代碼後,它已經完成了自己的反應計算,就可以得到實際要求的行爲,而不依賴於一些奇怪的招數setTimeout

這裏是全面推行這種模式的:

HTML

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

JS

// declare your reactive data source once to reuse the same in multiple places 
function messagesCursor(){ 
    return Messages.find(); 
} 

Template.myTemplate.helpers({ 
    messages: messagesCursor 
}); 

Template.myTemplate.onRendered(function(){ 
    this.autorun(function(){ 
    // we need to register a dependency on the number of documents returned by the 
    // cursor to actually make this computation rerun everytime the count is altered 
    var messagesCount = messagesCursor().count(); 
    // 
    Tracker.afterFlush(function(){ 
     // assert that every messages have been rendered 
     console.log(this.$(".messages") == messagesCount); 
    }.bind(this)); 
    }.bind(this)); 
}); 
+0

謝謝,很好的解決方案。我會測試這個。我擔心,如果計算完成,並不意味着所有元素都已經插入到DOM中。僅供參考,我實現了這種行爲,在自動運行功能中創建了一個區間。看到我的答案。 – ZuzEL

+0

好的,你的回答很好,但是因爲我不想每次收到新消息都滾動到特定消息,所以我無法使用它。看我的解決方案。 – ZuzEL