Best practice for sharing non-reactive data between Blaze templates?


#1

So let’s say I have a whole bunch of templates loading on the screen simultaneously, and they all need access to some data. The data rarely changes and doesn’t need to be reactive (let’s assume we’re guaranteed it won’t change while these templates exist).

What’s the best practice for sharing that data among the templates?

Option 1: Every helper in every template pulls the data from Mongodb. So in every helper we have:

Fruit.find({tasty: 1}).fetch();

Option 2: Every template pulls the data from Mongodb, saves to the template instance, and shares it with it’s own helpers. So in every Template we have:

Template.instance().tastyFruit = Fruit.find({tasty: 1}).fetch();

and then in its helpers we access that property.

Option 3: Pull the data from mongo once in a top-level layout template and pass it to all the sub-templates:

{{> subTemplate1 getTastyFruit}}

Option 4: Pull the data from mongo once in a top-level layout template, save it to the template instance, then call that from sub-templates (either in each helper, or resave in each sub-template during .onCreated()); Like:

Template.instance().tastyFruit = Template.instance().parentView.tastyFruit

Option 5: Save the data in a session variable (if it’s JSON-able) and access that in each template/helper.

Session.set('tastyFruit', ...);

Option 6: Create a variable in the global namespace, save the value to it in the top-level layout .onCreated() method and then access elsewhere.

var tastyFruit = null;
Template.mainLayout.onCreated(function(){tastyFruit = ...;});
Template.subTemplate1.helpers({eatThis: () => tastyFruit,});

Are there options I missed?

What’s the right way to do this in meteor/blaze?

Why?


#2

Make a global variable that’s accessible across everywhere if it’s in lib folder. Make sure it’s not reactive so that it hopefully doesn’t bleed over to server. using mongo for this is overkill. I’m uncertain myself how easily you can parse this to template view.


#3

I think that its a good practish to keep the templates agnostic to any kind of storage. This means pushing in data using template arguments is generally the cleanest way to go.

This makes the templates reusable no matter what the data retrieval mechanism is. The parent template should contain the mechanisms to retrieve needed data and push it to its children. This is what is often referred to as the smart component or template. Its coupled to the applications business logic.

I would use meteor methods to retrieve any static data from the server if needed


#4

Let’s assume the data is in mongo to begin with. It might change under some circumstances, it’s just guaranteed not to change while this particular template exists, so no need for reactivity.

I can still make a global variable after I pull it from Mongo, but is that the best way?


#5

cloudspider: so, you’re suggesting “Option 3”?


#6

Yes. Option 3. This will work according to the React wau and the Blaze way of doing it. Also fetching it using a collection is indeed the best way for meteor. If you don’ t want it to be reactive you can set reactive: false as option in your collection.


#7

you have no idea how expensive feeding it from db through publication and out to sub it is.


#8

It depends on what your source of publication is


#9

you must mean plain source file, or rather global variable?


#10

Alright. I will give a more detailed description.

Even if the data that feeds into my templates is not expected to be reactive, I would still follow practices on the UI that make my functions and templates reactive. It has many reasons. The main one being that even static data might not yet be there when the template is being rendered. The reactivity in this ensures a loading icon, a placeholder or similar feedback to tell the user that data is expected and coming.

As for the server / middle-ware part. It totally depends on the source of your data and what is the most easy to integrate. If all your data is stored in a Mongo instance, then it absolutely makes sense to use the same methods to publish data to your clientside. If you don’t need any reactivity then you can avoid any overhead by creating a custom publication like below:

Meteor.publish('example', function() { 
    const docs = Foo.find().fetch(); 
    docs.forEach(() => {
        this.added('foo', doc._id, doc)); 
    }
    this.ready(); 
});

Another way would be to use meteor methods. They behave more like REST endpoints and might give you a bit more simple code like below:

Meteor.methods({
    getFooData() {
         return Foo.find({}).fetch();
    }
});

Consider Redux or deal with the alternatives: Minimongo or Session
Redux is in fact a global object with some helpers that would contain a couple of actions and reducers. There’s a lot of tutorials out there, but the main point is keeping a global UI and Domain state that can be used by multiple components (React) or templates (Blaze).

Sessions are simple reactive variables that allow templates to listen to data changes. However, relying on them in templates will work, but its not really scale-able / clean etc, because You basically end up coupling your templates with Session glue.

Minimongo is also a good option and a bit more versatile then sessions. They allow querying and with Meteor its very easy to hook them up to subscriptions. You can use them also as clientside only collections. Very versatile. Better then sessions and my default choice for data coming from the server.

Just keep in mind. Use parent templates that act as smart, application specific templates. Those templates fetch data, are aware of any state and are generally custom for your application. All ‘generic’ templates should not have to be aware of any application logic besides their own internal state. Like a list template that expects an array of items from its parent template.