I have a list of tasks and I want to load a list of corresponding comments when I click one of the Tasks.
Iron router code:
Router.route('/taskComments/:_id', function () {
var item = Tasks.findOne(this.params._id);
this.render('commentList', {data: item});
},
{
name: 'taskComments',
fastRender: true
}
);
Template helpers:
Template.commentList.helpers({
comments: function(){
return Comments.find({taskID: this._id});
});
I am able to access the task id (this._id) in the above snippet, but it does not seem to work for onCreated:
Template.commentList.onCreated(function(){
this.subscribe("comments",this._id);
});
When I console log this it gives me the following object:
Notice that there is no _id and data is also null.
You can use Template.currentData() inside of this callback to access reactive data context of the template instance. The Computation is automatically stopped when the template is destroyed.
Template.commentList.onCreated(function(){
var self = this;
var dataContext = Template.currentData()
self.subscribe("comments",dataContext._id);
});
Related
I'm stumped here. I can't get it to find a collection from the onCreated method. If I log the data.source_id right before the call and then do the same lookup in the console, it finds it. Is there something special about onCreated or something? Am I just doing it wrong?
client/setup.js
Meteor.subscribe('source_elements');
Meteor.subscribe('internal_elements');
client/submit.js
Router.route('/element/submit', function() {
this.render('submit', {
data: {
source_id: this.params.query.source_id,
},
});
});
Template.submit.onCreated(function() {
var data = Template.instance().data;
var source_element = SourceElements.findOne({'_id': data.source_id});
console.log(source_element); // EMPTY!!
});
Template.submit.helpers({
element: function() {
var data = Template.instance().data;
var source_element = SourceElements.findOne({'_id': data.source_id});
console.log(source_element); // RESULT!!
return source_element;
},
});
Subscriptions are asynchronous. It looks like you are creating the template before the data has arrived at the client. By the time you execute the find in the console, the client has received the data.
Inside your onCreated function, you could use Tracker.autorun to specify a function that will be rerun when the SourceElements collection changes (that's what all template helpers do behind the scenes):
Tracker.autorun(function() {
var element = SourceElements.findOne({'_id': data.source_id});
console.log(element);
});
This function will be called immediately. At this point, findOne will probably return undefined because the subscription is not ready yet. Once the data has arrived, the function will be called again and you can process the returned elements.
Consider the following code :
Template.fullDoc.rendered = function() {
// Get triggered whenever the selected document id changes
this.autorun(function() {
var docId = isolateValue(function() {
return Template.currentData().selectedDoc._id;
});
...
});
}
This code doesn't work. Inside isolateValue(), Template.currentData() sometimes triggers an exception: Exception from Tracker recompute function: Error: There is no current view (this corresponds to the fact that Template.instance() returns null).
So how do you set a reactive dependency on a subpart of a template data context?
You could recreate the isolateValue behaviour in a way which doesn't cause Template.instance() to get set to null sometimes.
$ meteor add reactive-var
Template.fullDoc.rendered = function () {
var docIdVar = new ReactiveVar();
this.autorun(function () {
docIdVar.set(Template.currentData().selectedDoc._id);
});
this.autorun(function () {
var docId = docIdVar.get();
// ...
});
}
This makes use of the fact that setting a ReactiveVar to the same value it already has will not trigger an invalidation. (By default this only works for primitives; for objects you'll need to pass a custom equalsFunc when you construct the ReactiveVar. If _id is a string, you're fine. If it's ObjectID you probably aren't.)
Can someone see why the route is not subscribing to the publication. Profiles = new Meteor.Collection('profiles');
The mongo database does have documents in this collection, but the browser console still has a count of 0 in Profiles collection.
I am trying to tell the router, "subscribe to user-profile publication, when you are ready, render the 'profile' template. I also named the route 'profile.'
Now I have noticed that after typingsub = Meteor.subscribe('user-profile'); and then sub.ready(); I get the count of the collection. Otherwise the path is not subscribed. This behaviour has not occurred before.
lib/router.js
Router.plugin('loading', {loadingTemplate: 'Loading'});
Router.route('user/profile', {
name: 'profile',
waitOn: function () {
// return one handle, a function, or an array
return Meteor.subscribe('user-profile');
},
action: function () {
// this.ready() is true if all items returned from waitOn are ready
if (this.ready())
this.render('profile');
else
this.render('Loading');
}
});
server.js:
Meteor.publish('user-profile', function () {
return Profiles.find({userId: this.userId});
});
userId is a field in the Profiles collection. This profiles doc id is stored within the user.profile.experiences array for reference.
Meteor.userId is a function which returns the _id, not the _id itself, and you can't pass a function over DDP anyway. It should be:
waitOn: function () {
return Meteor.subscribe('user-profile', Meteor.userId());
}
I'm trying to access data passed from iron router in the javascript function
router.js
this.route('editOrganization', {
path: '/editOrganization',
waitOn: function() {
return [
Meteor.subscribe('organization', this.userId)
];
},
data: function() {
return Organizations.findOne();
}
});
now if I wanted to access a property of organization in html (editCompany.html) I can do the following
{{name}}
but how do I access that same property in the js file
Template.editOrganization.rendered = function() {
//how do I access name?
}
UPDATE:
so if I click a link to edit organization I can get the value via
this.data.name
However, if I reload the page (same url) it throws an error saying data is null.
It is accessible through the rendered function context.
Template.editOrganization.rendered = function() {
var name = this.data && this.data.name;
};
This is confusing for many people but you need to configure the router to actually wait for the subscriptions you returned with waitOn.
Router.onBeforeAction('loading')
You can read the author's explanation here:
https://github.com/EventedMind/iron-router/issues/554#issuecomment-39002306
Im new to Meteor and Im trying to figure out how to run a function after a collection change.
I have a route(iron router) that subscribes to a collection with waitOn. Which just waits for the subscrition to be ready before rendering which is what I want.
waitOn: function () {
return Meteor.subscribe('collection', this.params._id);
},
Any changes to the collection will be updated on all the clients and rendered automatically.
How would I run a function once the collection has changed?
You can use the onData hook, provided that you're returning that data using the data helper. E.g this is what a route may look like
this.route('routename',
path : '/abc',
waitOn: function () {
return Meteor.subscribe('collection', this.params._id);
},
data: function() {
return Collection.findOne({_id: this.params.id});
}
onData: function() {
//Do something when the data found by the above changes
}
});