Search code examples
javascriptmeteoriron-router

Meteor Iron Router WaitOn Subscription


I am really struggling with waiting on a subscription to load for a specific route before returning the data to the template. I can see on from the publish on the server that a document is found, but on the client there is no document.

If I do a find().count() on the publish, it shows 1 document found, which is correct, but when I do the count on the subscription, it shows 0 documents.

I have tried a number of different methods, like using subscriptions:function() instead of waitOn:function(), but nothing works.

Collections.js lib:

SinglePackage = new Mongo.Collection("SinglePackage");
SinglePackage.allow({
  insert: function(){
    return true;
  },
  update: function(){
    return true;
  },
  remove: function(){
    return true;
  }
});

Publications.js server:

Meteor.publish("SinglePackage", function(pack_id) {
 return Packages.find({shortId: pack_id});
});

Iron Router:

Router.route('/package/:id', {
  name: 'package.show',
  template: 'Package_page',
  layoutTemplate: 'Landing_layout',
  waitOn: function() {
    return Meteor.subscribe('SinglePackage', this.params.id);
  },
  data: function() {
    return SinglePackage.find();
  },
  action: function () {
    if (this.ready()) {
      this.render();
    } else {
      this.render('Loading');
    }
  }
});

Am I doing something very wrong, or is this just a complicated thing to achieve? One would think that waitOn would make the rest of the function wait until the subscription is ready.

Any help would be highly appreciated.


Solution

  • It appears that the data function is running before the subscription is ready. Even if the data function did run after the subscription was ready, it wouldn't be a reactive data source rendering the pub/sub here pointless. Here's a great article on reactive data sources.

    Referring to the example from the Iron Router Docs for subscriptions, you would do something like this:

    Router.route('/package/:id', {
      subscriptions: function() {
        // returning a subscription handle or an array of subscription handles
        // adds them to the wait list.
        return Meteor.subscribe('SinglePackage', this.params.id);
      },
    
      action: function () {
        if (this.ready()) {
          this.render();
        } else {
          this.render('Loading');
        }
      }
    });
    

    Then in your template.js:

    Template.Package_page.helpers({
      singlePackage() {
      // This is now a reactive data source and will automatically update whenever SinglePackage changes in Mongo.
        return Package.find().fetch();
      }
    }); 
    

    In your template.html you can now use singlePackage:

    <template name="Package_page">
      {#with singlePackage} <!-- Use #each if you're singlePackage is an array -->
        ID: {_id}
      {/with}
    </template>