Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Meteor helper called multiple times by single template variable

Tweets = new Meteor.Collection('tweets');

if (Meteor.isClient) {

  Meteor.subscribe('tweets');

  Template.Panel.helpers({
    items: function() {
      var days_tweets = Tweets.find();
      console.log(days_tweets.count());
      return days_tweets;
    });
  }

if (Meteor.isServer) {
  Meteor.publish('tweets', function() {
    return Tweets.find({}, {limit: 1000});
  });

The template:

<body>
<h1>This is a list of tweets</h1>
  {{> Panel}}
</body>

<template name="Panel">
<h2>A list of tweets sorted by size</h2>
    {{#each items}}
        <p>item</p>
    {{/each}}
</template>

And the console output when the page loads:

Tweet count:  0
Tweet count:  129
Tweet count:  272
Tweet count:  366
Tweet count:  457
Tweet count:  547
Tweet count:  672
Tweet count:  814
Tweet count:  941
Tweet count:  1000

So the helper function fires 10 times on page load (the number of times varies). Could anyone explain what is happening here? I can't find any reference to this, accept in situations where the helper is called from multiple {{ }} on the template. Also any way to stop it? Eventually I need to process the tweets in one go before before they are rendered.

like image 861
kendlete Avatar asked Nov 13 '14 16:11

kendlete


1 Answers

When you do a find meteor registers a dependency for that template helper on the collection you did a find on. Because of that dependency meteor will call the template helper for every modification to the collection.

If you haven't subscribed yet there is no data loaded in the client side copy of your mongo collection. Only when you call subscribe will meteor start pulling in the data from the server.

So the method is called multiple times because the subscribe keeps inserting new documents into your local copy of the mongo collection, triggering new calls to the template helper.

Best pattern to counter any problems this may give is by subscribing in the helper and using the ready method on the subscribe documentation. Ready is also reactive so when all data is pulled in ready will be changed to true and the helper will be called again.

  Template.Panel.helpers({
      items: function() {
          var ready = Meteor.subscribe('tweets').ready();
          var days_tweets = Tweets.find();

          return {
              data: days_tweets,
              ready: ready
          };
      });
  }

Template itself:

{{#with items}}
     {{#if ready}}
         {{#each data}}
             <p>item</p>
         {{/each}}
     {{else}}
         Show a spinner or whatever
     {{/if}}
{{/with}}
like image 80
Marco de Jongh Avatar answered Oct 13 '22 00:10

Marco de Jongh