Roee Gavirel
Roee Gavirel

Reputation: 19473

Meteor #each and session data

I have a template that is based on a async information, so I use the Session data in order to reactively render the view when the data arrive. Something like:

item.html:

<template name="item">
    {{#with item}}
        {{itemInformation.name}}
    {{/with}}
</template>

item.js

Template.item.created = function () {
    getItemData(this.data.item.id, function(data) {
        Session.set("itemInformation", data);
    });
}

Template.item.helpers({
    itemInformation: function() {
        return Session.get("itemInformation");
    }
});

This approach seems to work fine if I have one item template active. But if I use this approach in a #each loop I'm getting to collisions on the session data.

  1. Is there a "local" Session data I can use?
  2. What is the right approach to re-render view when based on a async data in #each loop?

Upvotes: 2

Views: 56

Answers (2)

Kyll
Kyll

Reputation: 7151

Session is a global named ReactiveDict used when you want to share data between various parts of your application. Since it's a global you probably don't want to clutter it too much.

Why even use a ReactiveDict? If you're going to store only one item per template then a ReactiveVar is the obvious way to go! Plus, ReactiveVar can contain anything, while ReactiveDict instances may only contain EJSON-able values.

Thus,

Template.item.created = function () {
    getItemData(this.data.item.id, data => {
        this.item = new ReactiveVar(data);
    });
}

Template.item.helpers({
    itemInformation: () => Template.instance().item
});

Note that each template will update according to subsequent set of their own ReactiveVar instance. If you wish to regularly update them with getItemData you don't have many options.
Since it's an async method you're out of luck. Your best bet is to regularly poll for data with Meteor.setInterval and item.set() the resulting data in your callback. I have done something similar here for a synchronous getter, you'd have to tweak the implementation.

Don't forget to Meteor.clearInterval in the onDestroyed callback of your template if you use the polling strategy described above.

Upvotes: 1

Paweł Jasiurkowski
Paweł Jasiurkowski

Reputation: 317

  1. You can create a ReactiveDict (https://atmospherejs.com/meteor/reactive-dict - Session actually uses it in its implementation) in the onCreated template callback (self.localSession = new ReactiveDict ()), and use it instead of Session (self.localSession.set('itemInformation', data)). You can access it in the template helper this way: Template.instance().localSession.get('itemInformation').

If it is just one item you want to store in the dictionary, you can also just use single ReactiveVar (https://atmospherejs.com/meteor/reactive-var) in the same manner.

  1. Just like you noticed, you need to set the async content in some reactive source, you can use the constructs I described above.

Your code:

Template.item.created = function () {
     var self = this;
     self.localSession  = new ReactiveDict ();
     getItemData(self.data.item.id}, function(data) {
         self.localSession.set("itemInformation", data);
    });
}

Template.item.helpers({
    itemInformation: function() {
        return Template.instance().localSession.get("itemInformation");
    }
});

Upvotes: 1

Related Questions