Meteor - how can I make this "reactive" using Deps?

On my client side, I show a list of users and a small diagram for each user item stored in the database (using the jQuery plugin called spark lines).

Drawing a chart is performed using the Template.rendered method

// client/main.js Template.listItem.rendered = function() { var arr = this.data.userPoints // user points is an array of integers $(this.find(".chart")).sparkline(arr); } 

Now I have a server-side Meteor method that is called on a regular basis to update user points.

 Meteor.methods({ "getUserPoints" : function getUserPoints(id) { // access some API and fetch the latest user points } }); 

Now I would like the chart to automatically update whenever the Meteor method is called. I have a method on a template that goes and calls this method Meteor.

 Template.listItem.events({ "click a.fetchData": function(e) { e.preventDefault(); Meteor.call("getUserPoints", this._id); } }); 

How to turn this code into "reactive"?

+7
javascript meteor
source share
2 answers

You need to use reactive data source ( Session , ReactiveVar ) together with Tracker .

Using ReactiveVar:

 if (Meteor.isClient) { Template.listItem.events({ "click a.fetchData": function(e) { e.preventDefault(); var instance = Template.instance(); Meteor.call("getUserPoints", this._id, function(error, result) { instance.userPoints.set(result) }); } }); Template.listItem.created = function() { this.userPoints = new ReactiveVar([]); }; Template.listItem.rendered = function() { var self = this; Tracker.autorun(function() { var arr = self.userPoints.get(); $(self.find(".chart")).sparkline(arr); }) } } 

Session Usage:

 if (Meteor.isClient) { Template.listItem.events({ "click a.fetchData": function(e) { e.preventDefault(); Meteor.call("getUserPoints", this._id, function(error, result) { Session.set("userPoints", result); }); } }); Template.listItem.rendered = function() { var self = this; Tracker.autorun(function() { var arr = Session.get("userPoints"); $(self.find(".chart")).sparkline(arr); }) } } 

The difference between these implementations:

A ReactiveVar is similar to a session variable, with a few differences:

ReactiveVars do not have global names, for example, "foo" in Session.get ("Foo"). Instead, they can be created and used locally for an example attached to a template instance, for example: this.foo.get ().

ReactiveVars are not automatically migrated using push requests, while session state.

ReactiveVars can contain any value, while session variables are restricted to JSON or EJSON.

A source

Grandfathers are outdated, but can be used.

+15
source share

The most easily scalable solution is to store data in a local collection - by passing an empty name, the collection will be both local and session, and therefore you can put whatever you want into it and still achieve all the advantages of reactivity. If you update the getUserPoints results in this collection, you can simply write a helper to get the corresponding value for each user, and it will automatically update.

 userData = new Meteor.Collection(null); // whenever you need to call "getUserPoints" use: Meteor.call("getUserPoints", this._id, function(err, res) { userData.upsert({userId: this._id}, {$set: {userId: this._id, points: res}}); }); Template.listItem.helpers({ userPoints: function() { var pointsDoc = userData.findOne({userId: this._id}); return pointsDoc && pointsDoc.points; } }); 

There is an alternative use of the Tracker package (formerly Deps), which will be quickly implemented here, but inconvenient to Tracker.Dependency essence, you can configure the new Tracker.Dependency to track changes at user points:

 var pointsDep = new Tracker.Dependency(); // whenever you call "getUserPoints": Meteor.call("getUserPoints", this._id, function(err, res) { ... pointsDep.changed(); }); 

Then just add a dummy helper to your listItem template (i.e. a helper that returns nothing by design):

 <template name="listItem"> ... {{pointsCheck}} </template> Template.listItem.helpers({ pointsCheck: function() { pointsDep.depend(); } }); 

While this will not return anything, it will cause the template to retrieve when pointsDep.changed() called (which will be when new data about the user's points is received).

+7
source share

All Articles