Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Meteor : wait until all templates are rendered

I have the following template code

<template name="home">
    <div class="mainBox">
        <ul class="itemList">
            {{#each this}}
                {{> listItem}}
            {{/each}}
        </ul>
    </div>
</template>

<template name="listItem">
    <li class="item">
        {{username}}
    </li>
</template>

And I'd like to execute a code once ALL of the "listItem" are rendered. There are about 100 of them. I tried the following

Template.home.rendered = function() {
   // is this called once all of its 'subviews' are rendered?
};

But it doesn't wait until all views are loaded.

What's the best way of knowing when all sub-view templates are loaded?

like image 547
ericbae Avatar asked Sep 10 '14 13:09

ericbae


1 Answers

This is how I proceed :

client/views/home/home.html

<template name="home">
  {{#if itemsReady}}
    {{> itemsList}}
  {{/if}}
</template>

<template name="itemsList">
  <ul>
    {{#each items}}
      {{> item}}
    {{/each}}
  </ul>
</template>

<template name="item">
  <li>{{value}}</li>
</template>

client/views/home/home.js

Template.home.helpers({
  itemsReady:function(){
    return Meteor.subscribe("items").ready();
  }
});

Template.itemsList.helpers({
  items:function(){
    return Items.find();
  }
});

Template.itemsList.rendered=function(){
  // will output 100, once
  console.log(this.$("li").length);
};

lib/collections/items.js

Items=new Mongo.Collection("items");

server/collections/items.js

insertItems=function(){
  var range=_.range(100);
  _.each(range,function(index){
    Items.insert({value:"Item "+index});
  });
};

Meteor.publish("items",function(){
  return Items.find();
});

server/startup.js

Meteor.startup(function(){
  Items.remove({});
  if(Items.find().count()===0){
    insertItems();
  }
});

We specify that we want to render our list of items only when the publication is ready, so by that time data is available and the correct number of li elements will get displayed in the list rendered callback.

Now the same using iron:router waitOn feature :

client/views/home/controller.js

HomeController=RouteController.extend({
  template:"home",
  waitOn:function(){
    return Meteor.subscribe("items");
  }
});

client/lib/router.js

Router.configure({
  loadingTemplate:"loading"
});

Router.onBeforeAction("loading");

Router.map(function(){
  this.route("home",{
    path:"/",
    controller:"HomeController"
  });
});

client/views/loading/loading.html

<template name="loading">
  <p>LOADING...</p>
</template>

Using iron:router is probably better because it solves a common pattern elegantly : we don't need the itemsReady helper anymore, the home template will get rendered only when the WaitList returned by waitOn will be globally ready.

One must not forget to add both a loading template and setup the default "loading" hook otherwise it won't work.

like image 66
saimeunt Avatar answered Oct 18 '22 23:10

saimeunt