Skip to content

Instantly share code, notes, and snippets.

@harrylove
Last active December 17, 2015 14:09
Show Gist options
  • Save harrylove/5622203 to your computer and use it in GitHub Desktop.
Save harrylove/5622203 to your computer and use it in GitHub Desktop.
Demonstration of reactive views in Meteor

You already know about reactive data sources. Views can be made reactive as well. Technically speaking, we make the view a reactive data source by storing it in the database and observing changes.

  1. Create a new app.
  2. Delete the default html, js, and css.
  3. Put the code below into a js file and run meteor.
  4. Then use the console to change either the View "html" property or the Number "val" property. (see code for examples)
  5. Try inserting and updating your own views and numbers.

N.B. The code is not an example of best practice, just a proof of concept. It relies on functions that are included in the Meteor Handlebars package. These functions could change or be removed in the future.

/*
Try these in the console:
var number = Numbers.findOne();
var viewId = number.templateId;
Views.update(viewId, { $set: { html: '<li>The value: {{val}}</li>' }});
Views.update(viewId, { $set: { html: '<li>My value is {{val}}</li>' }});
Numbers.update(number._id, { $set: { val: 22 }});
Numbers.update(number._id, { $set: { val: 25 }});
Views.insert(
{ html: '<li>The new value is {{val}}</li>' },
function(err, res) {
Numbers.insert({ val: 42, templateId: res });
}
);
Now change the first number to something greater than 42:
Numbers.update(number._id, { $set: { val: 48 }});
*/
Numbers = new Meteor.Collection('numbers');
Views = new Meteor.Collection('views');
if (Meteor.isClient) {
// You must define at least one template,
// either here or in html,
// otherwise Template is undefined
Meteor._def_template('main', null);
Deps.autorun(function() {
_.each(Views.find().fetch(), function(view) {
Meteor.call('compileTemplate', view.html, function(err, res) {
code = Handlebars.json_ast_to_func(res);
delete Template[view._id];
Meteor._def_template(view._id, code);
// Ideally, the session value would be a hash of the html
// but this works as a demo
Session.set(view._id, view.html);
}); // end call
}); // end each
}); // end autorun
Session.set('emptyListItem', null);
Deps.autorun(function() {
if (Session.get('emptyListItem') && Template.emptyListItem) {
var listItems = Meteor.renderList(
Numbers.find({}, { sort: { val: 1 }}),
function(num) {
if (Session.get(num.templateId)) {
Template[num.templateId] = Template[num.templateId] || Template.emptyListItem;
return Template[num.templateId]({ val: num.val });
}
},
Template.emptyListItem
);
var list = $('<ul>').html(listItems);
$(document.body).append(list);
} // end if
}); // end autorun
} // end isclient
if (Meteor.isServer) {
Meteor.methods({
compileTemplate: function(html) {
return Handlebars.to_json_ast(html);
}
});
Meteor.startup(function() {
if (Views.find().count() == 0) {
Views.insert({
_id: 'emptyListItem',
html: '<li>None</li>'
});
Views.insert({
html: '<li>The value is {{val}}</li>'
}, function(err, res) {
Numbers.insert({
val: 21,
templateId: res
});
}); // end view insert
} // end if
}); // end startup
} // end isserver
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment