1
<template name="FrameItems">
  <div class="frame-items">
    {{#each frames}}
      {{> FrameItem}}
    {{/each}}
  </div>
</template>

In the above example, I want to know when all FrameItem templates inside FrameItems template have been rendered. I thought onRendered of the parent would be invoked when all the child templates have been rendered, but it was just called right away. What's the conventional way of making sure all the child templates are rendered?

Maximus S
  • 10,759
  • 19
  • 75
  • 154
  • There's several DIY ways to do this if you search around, but it would be nice if there was a core Meteor function for this as it's really common and helpful if you're using JS plugins that can't initialize until all DOM elements are inserted. FYI I wrote a "add ranking and compare to a count" solution here: http://stackoverflow.com/questions/14548581/callback-when-all-template-items-finished-rendering-in-meteor But it requires any JS code be ran IN the child template's `.onRendered` callback, not the parent. – evolross Jul 28 '15 at 20:41

2 Answers2

0

Here is how I would proceed:

  1. You create a pageSession reactive variable or reactive dictionary entry. Let's call it lastRendered.
  2. You update it in the onRendered function of your FrameItem template using the _id of the related frames item. This way, each time a FrameItem template is rendered, you now which one it is.
  3. You create an helper in your parent template watching your lastRendered reactive variable and checking if it matches your last frames item. It could look like that (untested code):

    lastFrameIsRendered: function() {
      var lastId = frames.find().limit(1).sort({$natural:-1}).fetch()._id;
      return pageSession.get ("lastRendered") === lastId;
    },
    

Alternatively, if you need to get a feedback in your parent template onRendered function, you can wrap this code into a this.autorun(function() { (tracker) like this:

var lastId = frames.find().limit(1).sort({$natural:-1}).fetch()._id;
this.autorun(function() {
  if (pageSession.get ("lastRendered") === lastId) {
  //do your stuff
  }
});

It will be executed each time there is a change in your parent template.

Billybobbonnet
  • 3,156
  • 4
  • 23
  • 49
0

One way to do it is to use a counter and increment it until it reaches a certain value.
Here the counter would in Session and incremented until it reaches the length of your Frames iterable thing:

Template.FrameItems.onRendered(function() {
  Session.set('frameCounter', 0);
});

Template.FrameItem.onRendered(function() {
  Session.set('frameCounter', Session.get('frameCounter') + 1);
});

Then you simply use a tracker:

//Where template is your template instance, for example 'this' in an onCreated callback
template.autorun(function doStuffWhenFramesRendered(computation) {
  if(Session.get('frameCounter') === template.frames.length) {
    doStuff();
    //Stop observing
    computation.stop();
  }
});

Note that it takes into account the fact that FrameItem may render at weird times (avoiding race conditions if any), but it doesn't take into account new frames. To take those into account you would not stop the computation.

Kyll
  • 7,036
  • 7
  • 41
  • 64