I have a list of \'s which gets populated with a find() using Meteor.startup as you see below. Then I\'m getting all the data attributes of these
&l
Meteor.startup
Meteor.startup()
runs only once, its run on the client and server. So when the browser loads and the initial DOM is ready or the server starts. As Sohel Khalifa said you place initialization functions here. Don't define templates in here because the the templates need to be ready before this function can be fired.
Template.myTemplate.onRendered(function() {... })
This is run when meteor has finished and rendered the DOM. Additionally is run each time the HTML changes within the template. So for each item in your list in a subtemplate/a change in an item/update,etc as well as the list you will see the console.log return something if you use it to check. It will return null
/undefined
when calling for data sometimes (which i'll explain):
Does this mean all the DOM is ready? NO!:
I think this is what might be causing you a bit of trouble. If you use external APIs such as Google maps, they might still render the map. the Template.myTemplate.rendered()
means Meteor has finished rendering the template with the reactive variables necessary. So to find out when your Google maps might be ready you need to hook into the Google maps API. Have a look at this question
Using Meteor.subscribe
The reason you might get null
/undefined
while using rendered
is because this is the process meteor usually renders data into templates
You are basically calling console.log(getMarkers());
before the subscription is complete, which is why you get null
/undefined
Meteor uses this summarized process with templates & reactive data:
So if at process 1) for a very short time you will have no data yet, which is why you might get null
(such as in your code) & at the first render. To get past this you should use Meteor.subscribe
's callback which is run when all the data is downloaded from the server: e.g
Meteor.subscribe("lists", function() {
//Callback fired when data received
});
Note: Before you use this you should read the docs on using subscriptions as you need to remove the autopublish
package, as well as make a corresponding Meteor.publish
function on the server. While this may seem tedious you may end up doing it anyway to give your users their own lists &/or implement some kind of security.
Suggested edits to your code:
You are doing DOM traversing in the right place, Template.mytemplate.onRendered(function()..
but you also need to hook into Google Maps' API to capture when their map is finished drawing. You should also use Meteor.subscribe
to make sure you get the timing right and not get null
/undefined
.
Make sure you put your Template helpers in a Meteor.isClient
but not in a Meteor.startup
because Meteor.startup is fired after your initial DOM is ready (the intitial is the first but before its changed by reactive variables or a router) so your template definitions need to run before this stage.
Many thanks Akshat for detailed answer)
I have more complicated case of using Meteor.subscribe, i have template which includes images from DB. So i need to wait for data from two collection iamges and news(all other data here).
I get my DOM ready in this way:
imageIsLoaded = new Promise(function(resolve){
Meteor.subscribe('images',function(){
resolve()
});
});
newsIsLoaded = new Promise(function(resolve){
Meteor.subscribe('news',function(){
resolve()
});
});
Template.newsList.onRendered(function(){
Promise.all([imageIsLoaded, newsIsLoaded]).then(function() {
// DOM IS READY!!!
newsServices.masonryInit();
})
});
Template structure:
<template name="newsList">
{{#each news}}
{{> news_item}}
{{/each}}
</template>
The best way to do this is to put code into Template.x.rendered() and use a Session reactive variable to track if the code has been run or not. For example, you could go about this like so:
Template.x.rendered = function () {
if (Session.get('doneMarkers') == null) {
// Do your stuff
if (getMarkers() != null) {
Session.set('doneMarkers', 'yes');
}
}
});
function getMarkers() {
var coordinates = {};
coordinates = $('li.message').data();
return coordinates;
}
If you ever want to rerun that part of the code, you only have to call:
Session.set('doneMarkers', null);
The reason why it returns null
as a result is, you have placed it in Meteor.startup()
. It actually runs before the data is loaded from the server. So the lists.find()
returns null.
The Meteor.startup()
is a place for initializing your global variables, reative sessions and subscribing to the primary bunch of data from the server. Everything you write there will be executed once, right after the client starts up.
The Template.myTemplate.rendered()
is a special helper provided by meteor that runs everytime when the corresponding data has changed, it is mainly used for getting attributes or manipulating DOM elements contained within that template.
So, place your helper code outside in common isClient()
area. And use .rendered()
helper to traverse the DOM, and getting or manipulating attributes of DOM elements.