I wonder is there any way to know if #each loop is "ready". By "ready" I mean it rendered all nodes and inserted into the DOM. I don't even speak about onRendered
callback (old rendered
). I tried
<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)
})
But it does not work either. I don't want to use timers.
UPDATE
messages
is a collection of text messages for current dialog, dialogId
is a reactive var stored in the Session
.
Template.myTemplate.onCreated(function(){
var self = this;
self.autorun(function(){
self.subscribe("messages", Session.get("dialogId"))
})
})
So if someone changes dialogId, myTemplate loads another dialog messages, and I want to know when this messages are ready, to scroll to a specific message. Simple onReady
does not work, since I can not call scrollTop accurately before all messages are rendered and got its own height.
@saimeunt provided elegant solution, but I implemented it other way, maybe someone find it helpful too.
Since I don't want my code been executed everytime a new message arrives, I can not trigger scrolling after autorun is finished. (You would say, OK, do it in autorun that depends only on
dialogId
. - then I can not get exact message count of this dialog since subscription should take some time)HTML
JS
There's no easy way to get notified when a Spacebars
{{#each}}
block has done rendering into the DOM every item its spanning.The best solution is to use another reactive computation (
Tracker.autorun
) to observe your messages cursor changes.Everytime your messages list is modified, you can run arbitrary code after every other reactive computations are done performing whatever their job is, using
Tracker.afterFlush
.The
{{#each}}
block is one of those computations, whose role is to listen to the reactive data source you give it as argument and rerender itsTemplate.contentBlock
as many times as items fetched from the source being iterated over, with the current item as current data context.By listening to the exact same reactive data source as the
{{#each}}
block helper and running your code AFTER it has finished its own reactive computation, you can get the actual requested behavior without relying on some weirdsetTimeout
tricks.Here is the full implementation of this pattern :
HTML
JS