How to show an animation (eg hourglass) whilst data from published collections is transferred?

I only could find an old article on this topic and when I implemented it I got the warning message that the method used was outdated (EDIT: SVG’s SMIL animations (, , etc.) are deprecated and will be removed. Please use CSS animations or Web animations instead.)

So how is everyone making that waiting period more transparent to the user? Are you showing a custom animation, a text or an hourglass? If so, how can this be achieved (links to articles or your own code is appreciated)?

Sorry for the noob question, still learning frontend dev every day.

Thanks in advance!

1 Like

You’re looking for the subscription handle’s ready event.

http://docs.meteor.com/#/full/meteor_subscribe

const handle = Meteor.subscribe('some-publication');

if (!handle.ready()) {
  // render some loading state
}
1 Like

Thanks for your explanation on the handle’s ready event. My question is more about the quoted part, how to render some loading state. I have no clue how to achieve that, is there a package for this or a Meteor function that I’ve overlooked?

Hey @a4xrbj1

Noob-Questions are the best questions, no worries! :slight_smile:
I remember asking myself the exact same question many moons ago.
(still a noob though :D)

This is the pattern I now normally use for this:

###Step 1 (optional): Create a Template for your loader icon/animation
I prefer to use svg icons for this.
You an find some good ones on here on codepen.io, but feel free to just use this one. (It uses SVG’s SMIL animations though, so you’ll get the same warning)

<template name="loader_circle">
	<svg version="1.1" id="loader-1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="40px" height="40px" viewBox="0 0 40 40" enable-background="new 0 0 40 40" xml:space="preserve">
	<path opacity="0.2" fill="#000" d="M20.201,5.169c-8.254,0-14.946,6.692-14.946,14.946c0,8.255,6.692,14.946,14.946,14.946
		s14.946-6.691,14.946-14.946C35.146,11.861,28.455,5.169,20.201,5.169z M20.201,31.749c-6.425,0-11.634-5.208-11.634-11.634
		c0-6.425,5.209-11.634,11.634-11.634c6.425,0,11.633,5.209,11.633,11.634C31.834,26.541,26.626,31.749,20.201,31.749z"/>
	<path fill="#000" d="M26.013,10.047l1.654-2.866c-2.198-1.272-4.743-2.012-7.466-2.012h0v3.312h0
		C22.32,8.481,24.301,9.057,26.013,10.047z">
		<animateTransform attributeType="xml"
			attributeName="transform"
			type="rotate"
			from="0 20 20"
			to="360 20 20"
			dur="0.5s"
			repeatCount="indefinite"/>
		</path>
	</svg>
</template>

Step 2: Create the Logic

Subscribe to your Collection on the Template Level.
I find this is generally a good idea and its also recommended in the Guide.

Template.MyTemplate.onCreated(function() {
  this.autorun(() => {
    this.subscribe('MyCollection');
  });
});

Now you have Access to Template.subscriptionsReady, which let’s you do something like this.

<template name="MyTemplate">
  <div class="mytemplate">
    {{#if Template.subscriptionsReady}}
      Yout content
    {{else}}
      {{> loader_circle}}
    {{/if}}
  </div>
</template>

Step 3: Test the Loader

You can use Meteor._sleepForMs(1000); in your publication to simulate a slow connection and see the loader in action.

Meteor.publish('MyCollection', function() {
	// Simulate slow Connection
	Meteor._sleepForMs(1000);
	// Publish Collection
	return MyCollection.find();
});

Hope this helps! :slight_smile:

1 Like

Great answer, very helpful and the link to CodePen is awesome. Just from a quick look I already fell in love with this simple but still extraordinary animation: http://codepen.io/flurrd/pen/QwWvwq

Hope this one also doesn’t give the warning about the SMIL

Uh! Yeah, thats a nice one! :smiley:
No, looks like this one uses css animations instead, so you should be good. :slight_smile:

I don’t understand this code. Is this coffeescript or ECMAscript2015? What would be the equivalent of “normal” Javascript?

Ok @nilsdannemann I’ve entered your script but it actually never goes into the else branch. This is the code in the puzzle.html

<template name="puzzle">
    {{#if Template.subscriptionsReady}}
        // rest of the html content
    {{else}}
        debugger;
        {{> loader_circle}}
    {{/if}}
</template> 

So it never reaches the debugger statement. The pub/sub works seamless (worked before already) and it takes maybe 1-2 seconds before it populates the content of this template. But in the meantime there is no loading spinner or anything (I used your example above). Like I said, it never enters the else branch.

The only difference to your code is in that I need to subscribe to a remote connection, as my server is a different app than the client:

Template.puzzle.onCreated(function () {
    'use strict';
     var kitUser;
    kitUser = Session.get('kitUser');
    Session.setDefault('pFilter', 'All cards');
    remote.subscribe('cards', Meteor.userId(), function () {
        console.log('onCreated - Number of cards docs: ' + Cards.find({ kit: kitUser, read: false }).count());
    });
});

Any comments, errors that I overlooked?

Sorry, a bit short on time right now, but for this part:

Yes, this uses a ECMAscript2015 Arrow function, so it’s not “normal” javascript.

To use this you neet the es5-shim and ecmascript packages, which should come with Meteor 1.3 by default.

You can install them manually via:
meteor add es5-shim
meteor add ecmascript

On the other hand you can just use plain old js, which I think would look like this:

Template.MyTemplate.onCreated(function() {
  this.autorun(function() {
    this.subscribe('MyCollection');
  });
});

Hope this helps.
I’ll write a reply to your other question later.

Hm, since in here this refers to the template, I think you’ll use it to get access to Template.subscriptionsReady.

Template.MyTemplate.onCreated(function() {
  this.autorun(function() {
    this.subscribe('MyCollection');
  });
});

Not sure what remote.subscribe does in your case.

I’d try it with a very simple, standard pub/sub and see if this works first.
After that try to implement your custom remote subscription.

Hope this helps. :slight_smile:

Ok, I’m not using the this.autorun part but my code subscribes without problems to the collection on the other app. Remote is just the handle that is returned from the DDP.connect as in remote = DDP.connect(worker_host); with worker_host being an URL.

Sorry for the late reply.
Time tends to be on short supply these days :slight_smile:

Alternatively you could probably create a helper for this.

Template.MyTemplate.helpers({
	subscriptionReady: function() {
		const handle = Meteor.subscribe('MyCollection');
		const isReady = handle.ready();
		if (isReady) {
			return true;
		}
	}
});

If I’m not mistaken in your case you would just replace the Meteor.subscribe() with your remote.subscribe.

But as mentioned I have no experience with remote.subscribe(), so I’m not sure it this is the right approach. :-/

Then you would place it like so:

<template name="MyTemplate">
	{{#if subscriptionReady}}
		Your Content
	{{else}}
		{{> loader_circle}}
	{{/if}}
</template>

Hope this helps.