18

I have a template, task_list, that looks like this:

{{#each tasks}}
    {{> task}}
{{/each}}

Template.task_list.tasks returns a collection and in the ui, it seems to take a bit of time to load.

While the collection is loading, I'd like to show a loading indicator.

Any ideas on how I might be able to do that?

BTW, I did try the templates' rendered event on task_list template, however it gets fired before the list is actually loaded. I also tried using rendered on the task template but it seems to never get called.

Dan Dascalescu
  • 143,271
  • 52
  • 317
  • 404
Gezim
  • 7,112
  • 10
  • 62
  • 98
  • I was wondering about the same issue at [How can the delay before displaying meteor collections be best addressed?](http://stackoverflow.com/questions/12773672/how-can-the-delay-before-displaying-meteor-collections-be-best-addressed) – Dan Dascalescu Oct 14 '12 at 06:43

3 Answers3

32

Meteor 1.0.4 update: Now that template-level subscriptions are available and the preferred pattern to using iron:router or standalone subscriptions,

There is a complementary function Template.instance().subscriptionsReady() which returns true when all of the subscriptions called with this.subscribe are ready.

Inside the template's HTML, you can use the built-in helper Template.subscriptionsReady, which is an easy pattern for showing loading indicators in your templates when they depend on data loaded from subscriptions.

Example:

Template.notifications.onCreated(function () {
  // Use this.subscribe inside onCreated callback
  this.subscribe("notifications");
});
<template name="notifications">
  {{#if Template.subscriptionsReady}}
    <!-- This is displayed when all data is ready. -->
    {{#each notifications}}
      {{> notification}}
    {{/each}}
  {{else}}
    Loading...
  {{/if}}
</template>

This is better than having a generic loading template for the whole page, because the loading section is localized to the part of the page that actually has new data.


Pre-Meteor 1.0.4:

The idea is to pass an onReady function to Meteor.subscribe:

Meteor.subscribe('tasks', function onReady() {
  Session.set('tasksLoaded', true);
});

Then, make your template depend on the tasksLoaded session variable. In the client JavaScript:

Template.task_list.helpers({
  tasksLoaded: function () {
    return Session.get('tasksLoaded');
  }
});

In your template:

<template name="task_list">
  {{#if tasksLoaded}}
    {{#each tasks}}
      {{> task}}
    {{/each}}
  {{else}}
    <img src="http://viewvc.svn.mozilla.org/vc/addons/trunk/bandwagon/skin/images/spinner.gif?revision=18591&view=co&pathrev=18591">
  {{/if}}

UPDATE: With iron-router you have a direct option to specify a loading template which will be displayed while the subscription is loading.

Community
  • 1
  • 1
Dan Dascalescu
  • 143,271
  • 52
  • 317
  • 404
  • 1
    Thanks, Dan. This was spot on. – Gezim Oct 15 '12 at 01:33
  • the function is fine but how do you make a callback when all the subscriptions are ready? – malhal Aug 01 '15 at 10:20
  • Related question: I want to have a mini-loader in my navbar in addition to an `iron-router` style loader on the main page that's loading. Is there a way in my `header` template to somehow check for the **rest** of my templates on the page being ready? All I can figure out is how to wait for *that* template that the loader is actually in - which is loaded very quickly. I tried absolute positioning CSS to just "put" my mini-loader up in the navbar from my `iron-router` loader but it gets messed up on certain pages and transitions. Having it actually in my header would be ideal. – evolross Sep 02 '15 at 19:33
  • 1
    What would be the way to do it if I use subscriptions through iron:router? I re-use components on multiple routes, while each route loads different data. So subscribing in the router makes sense to me for my use case. – Laran Evans Feb 12 '16 at 07:29
5

Dan's answer was definitely spot on, but I want to remind that I belive autopublish package has to be removed for it to actually work.

meteor remove autopublish

Plus, I recommend spin package for a nice looking spinner.

Community
  • 1
  • 1
Cagdas Can
  • 248
  • 2
  • 7
2

There have been some nice packages released in the meantime. Check out these two:

  1. Spin - displays a spinning wheel. With Iron Router, you can specify a loading template which shows the spinning wheel.
  2. Iron Router Progress - shows a progress bar on the top of the page (Youtube style)

They both work pretty much out of the box, have a look at their documentation for more advanced options.

Jan Klimo
  • 4,643
  • 2
  • 36
  • 42
  • Those packages do come in handy. In the meantime, Meteor has released v1.0.4, which brings in template-level subscriptions and a `Template.subscriptionsReady` helper. See [my answer](http://stackoverflow.com/a/12880255/1269037) for more details. – Dan Dascalescu Apr 05 '15 at 19:38