[SOLVED] Blaze Issue - Reactively Update Static Data Cursor Without A Pop or Loader?


#1

I’m having a funny Blaze issue with reactively updating a static data cursor that’s populated using a Meteor Method that gets reran using a ReactiveVar. I want my refreshed data to just update without using a loader or have a pop. I just want it update instantly how it does with pub-sub.

In my HTML template I have:

{{#unless chatsLoading}}
   {{#each chats}}
      <li>{{body}}</li>
   {{/each}}
{{else}}
  {{> loading}}
{{/unless}}

In my template code I have a helpers:

chats: function() {
   return Template.instance().chats;
}

chatsLoading: function() {
   return Template.instance().chatsLoading.get();
}

I set the chats array using a Meteor Method reactively triggered by a ReactiveVar in an autorun (again, intentionally not using pub-sub):

// This gets updated elsewhere in my app and reactively triggers a requery below
instance.queryChats = new ReactiveVar(true); 
instance.chatsLoading = new ReactiveVar(true);  // Used to redraw the template #each

instance.autorun(function() {
   if(instance.queryChats.get()) {
      instance.chatsLoading.set(true);  //  Set that the chats are loading
      Meteor.call("queryChats", someId, function(error, result) {
         instance.queryChats.set(false);  //  Set the query flag to false
         instance.chats = result;  //  Method returns array of chats
         instance.chatsLoading.set(false); // Unset that the chats loading
      });
   }
});

The problem I’m experiencing is there doesn’t seem to be a way to update the template’s {{#each chats}} with the new data from the Meteor Method result without using the above HTML {{#unless chatsLoading}} call. The way the code is designed above, whenever my autorun reruns the Meteor.call, the template will temporarily show the {{> loading}} template, which I don’t want. I want my data to just “update” without a glitchy loader or blink off (if I didn’t use the loader above). The issue though is if I don’t use something like {{#unless chatsLoading}} above, then the HTML template will not rerender the {{#each}} and thus update the data because I’m not using reactive pub-sub. Just calling instance.chat = result does not redraw the HTML how it does if you’re using pub-sub.

So the only thing I’ve found that makes this work how I want is to do the following, which just seems really hacky:

{{#unless chatsLoading}}
   {{#each chats}}
      <li>{{body}}</li>
   {{/each}}
{{else}}
  {{#each chats}}
      <li>{{body}}</li>
   {{/each}}
{{/unless}}

This strange approach will indeed redraw the template (because it uses the chatsLoading helper) but it also doesn’t pop, blink, or call a loader because both sides of the chatsLoading boolean draw the data.

Just curious if I’m missing a better way to do this and not do something so hacky.


#2

I figured it out, the solution is very simple actually. Just use a ReactiveVar on the data cursor as well. So you add:

instance.chats = new ReactiveVar();

Then in the return of the Meteor Method do:

instance.chats.set(result);

And in the helper:

Template.instance().chats.get();

Problem solved. Now you don’t need the loading animation unless you want it and the data updates instantly as soon as it’s set in the callback of the Meteor Method.

I was overthinking it.