Reputation: 29179
In my Meteor app I have this rendered
function which needs to access a specific collection. Assume I have a collection ToDos
ToDos = new Meteor.Collection('todos');
if (Meteor.isClient) {
Meteor.subscribe('todos');
}
if (Meteor.isServer) {
Meteor.startup(function () {
Meteor.publish('todos', function () {
return ToDos.find({});
});
});
}
Now in a rendered function I want to do something like this
Template.todos.rendered = function () {
var todo = ToDos.findOne({...});
if (todo) {
$('[datepicker]').datepicker('setDate', todo.date);
}
}
The problem I have is that when rendered
is called, todo
is undefined
and this function is only called once. Is there a fix for this ? Can Deps.autorun
help ?. If yes, how ?
On the other hand, if I could just listen for the ToDos
only I could update the datepicker there!
Upvotes: 1
Views: 696
Reputation: 927
Assuming you've got a simple app with only one page
A possible implementation with deps
if (Meteor.isClient) {
Meteor.startup(function() {
Meteor.subscribe('todos');
Deps.autorun(function(e) {
var todo = ToDos.findOne({...});
var $picker = $('[datepicker]');
if (!!todo && !!$picker) {
$picker.datepicker('setDate', todo.date);
}
});
});
}
Meteor renders the template first and then grabs data. So when the data changes you have to go and set your data picker.
Collection.observe might be of interest to you too. You can get a callback every time data is added, changed, deleted, etc.
var todo = ToDos.find({...});
var handle = todo.observeChanges({
added: function (id, todo) {
// do stuff on added
},
removed: function () {
// do stuff on removed
}
});
Upvotes: 1
Reputation: 8013
Yes, this is a potentially annoying problem in Meteor. Essentially, whilst the handle that your Meteor.subscribe
call returns has a ready
method which will tell you if the collection is ready or not, usually your rendered
callbacks will have run by the time it returns true
, so it's not very useful in this case. You can use the onReady
callback in your subscribe call in some cases, and it's even possible to plug into a template's data context from elsewhere if you know the template instance exists and do anything you could in the rendered
callback, but this would probably be a very messy way of dealing with the problem you present (because if there was ever a case in which the collection was ready before the DOM had been rendered it would fall down).
SOLUTION:
As is often the case, iron router is the best solution here, as it allows each route to have a waitOn
callback, which you can use to specify which subscriptions need to be ready()
before the page begins to render (although you can wait on anything with a ready
callback, not just subscriptions). That way, you always know that your Collection.find
will return what you're expecting when your rendered
callbacks first run.
Upvotes: 1