Search code examples
meteorpublish-subscribe

meteor: publication / subscription not working


I can't for the life of me figure out why nothing shows up client-side in this meteor app. I have tried all the advise in all the related topics and nothing seems to work. I'm using msavin:mongol and I don't even see the subscription on the client at all, despite console.log() debug output indicates that it is there with the current number of entries.

/imports/api/friends.js:

export const Friends = new Mongo.Collection('friends');
Friends.deny({ insert() { return true; }, update() { return true; }, remove() { return true; } }); // access to collections only through method calls

/imports/api/server/friends.js:

import { Meteor } from 'meteor/meteor';
import { Friends } from '../friends.js';

Meteor.publish('friends.all', function(){
    return Friends.find();
})

/imports/ui/pages/friends.js:

import { Friends } from '/imports/api/friends.js';
import './friends.html';


Template.friends.onCreated(function() {
    this.subscribe('friends.all');
});

Template.friends.helpers({
    friends: ()=>{ return Friends.find(); }
});

/imports/ui/pages/friends.html:

<template name="friends">
  <h1 class="ui header">Friends</h1>
  {{#if Template.subscriptionsReady}}
      <h2 class="ui heder">friends list:</h2>
      <div class="ui list">
        {{#each friend in friends}}
            <div class="item">{{friend.name}} ({{friend.email}})</div>
        {{/each}}
      </div>
  {{/if}}
</template>

The "friends list" header shows up, so the subscriptionsReady call returns, but I don't get any data (verified that data exists in the database).

I've also tried moving the subscription into the router (using ostrio:flow-router-extra) and there the waitOn() function never returns when I add the subscription

What is going on here?


Solution

  • If you are missing to include your publication on the server then your client's subscription will immediately be 'ready' but there will be no error message.

    This can cause a lot of confusion when creating templates with template-level-subscriptions.

    In order to check if a publication exists or not, you can use on the server after start the (undocumented) server.publish_handlers array. It keeps a record of the registered publications.

    Meteor.startup( () => {
      console.log( Meteor.server.publish_handlers );
    });
    

    This comes in very handy, if you have designed your api in way that it keeps track of its intended publications:

    friendsdef.js

    // definition file for Friends collection and it's
    // surrounding functionality
    
    export const FriendsDef = {
      collectionName: 'friends',
      schema: { ... },
      methods: { ... },
      publications: {
        all: {
          name: 'friends.all'
        }
      }
    }
    

    someServerStartup.js

    // make sure on startup, that all intended
    // publications are registered
    
    Meteor.startup( () => {
      Object.values( FriendsDef.publications).forEach( pub => {
        if (!Meteor.server.publish_handlers[pub.name]) {
          throw new Error('publication should exist, but does not');
        }
      });
    });
    

    The same works with method_handlers for methods. Use these data structures with a well defined API and you will decrease errors of missing includes or misspelled names a lot.