Search code examples
meteormeteor-blaze

Meteor keep old subscribed data until new subscribed date is ready


My table flickers because my subscription is re-subbing in an autorun. When the subscribe is called again in the autorun, my data disappears and I have an empty table until the Data.find() runs again. How can I keep the data UNTIL the new data is ready?

Template.table.onCreated(function () {
  this.autorun(() => {
    if (Session.get('selectedItem') && selectedSubItem.get()) {
      this.subscribe('dataOverview', Session.get('selectedItem'), selectedSubItem.get()._id);
    }
});

Template.table.helpers({
  collection () {
    return Data.find({"item._id": Session.get('selectedItem')._id, "subItem._id": selectedSubItem.get()._id});
  },

I also tried a different way, to see if it was actually a subscription data problem with the code below. The table is empty after the autorun, before the find runs a second time.

Template.table.onCreated(function () {
  this.autorun(() => {
    if (Session.get('selectedItem') && selectedSubItem.get()) {
      this.subscribe('dataOverview', Session.get('selectedItem'), selectedSubItem.get()._id, () => {
        let cursor = Prjs.find({"app._id": Session.get('selectedApp')._id,"release._id": selectedRel.get()._id});
        this.tableData.set(cursor);
      });
    }
});

Template.table.helpers({
  collection () {
    return Template.instance().tableData.get();
  },
});

From the meteor guide

The server explicitly waits until all the data is sent down (the new subscription is ready) for the new subscription before removing the data from the old subscription. The idea here is to avoid flicker—you can, if desired, continue to show the old subscription’s data until the new data is ready, then instantly switch over to the new subscription’s complete data set.

What this means is in general, when changing subscriptions, there’ll be a period where you are over-subscribed and there is more data on the client than you strictly asked for. This is one very important reason why you should always fetch the same data that you have subscribed to (don’t “over-fetch”).

I want to "continue to show the old subscription's data until the new data is ready, then instantly switch over to the new subscription's complete data set" but how do I do that?


Solution

  • The best solution to solve this problem is to use a subscription caching package, such as:

    meteorhacks:subs-manager was the original solution, and is one of the many packages developed by Arunoda. It is a solid choice, but be aware that it is no longer being actively maintained.

    ccorcos:subs-cache is essentially a fork of meteorhacks:subs-manager that has fixed some issues, and is currently being maintained.

    Both packages require a slightly different syntax when you subscribe on the client, and provide a cache for your subscriptions which will eliminate the flickering you describe in your question.

    // using ccorcos:subs-cache
    
    let subsCache = new SubsCache({
      expireAter: 5,  // minutes
      cacheLimit: 10
    });
    
    Template.table.onCreated(function () {
      this.autorun(() => {
        if (Session.get('selectedItem') && selectedSubItem.get()) {
          subsCache.subscribe('dataOverview', 
                              Session.get('selectedItem'),
                              selectedSubItem.get()._id );
        }
    });