Nyxynyx
Nyxynyx

Reputation: 63687

How to retrieve Meteor.js Collection then pass it to a function after DOM loads

How can a query on the collection be executed first, then execute another function when a particular div has been rendered?

If I were to do the following, I get an error from .highcharts() stating that it is unable to find the div #chart.

main.html

<template name="chart">
    <div id="chart">{{init}}</div>
</template>

main.js

Template.chart.init = function() {
    // Get results of query first
    var data = myCollection.find();

    data.forEach(function(row) {
        console.log(data.price); // yes we received the collection
    });

    // Then pass to function
    $('#chart').highcharts(data);
};

Now If I were to call the function highcharts() after the template dom has been rendered via Template.chart.rendered as shown below, I get an error stating that the variable data is not found.

Template.chart.init = function() {
    var data = myCollection.find();

    data.forEach(function(row) {
        console.log(data.price);
    });
};


Template.chart.rendered = function() {
    $('#chart').highcharts(data)
}

Here it appears that Template.chart.rendered runs before Template.chart.init. How can I run the highcharts function after data has been retrieved from mongo?

Upvotes: 3

Views: 2005

Answers (1)

jrullmann
jrullmann

Reputation: 2978

Your first example doesn't work because Meteor calls your helper functions as it figures out what to render. At that point your chart template doesn't yet exist in the DOM.

Your second example doesn't work because of a scope problem. You're trying to use a variable in the rendered handler that only exists in init.

This should work:

Template.chart.rendered = function() {
  $('#chart').highcharts(myCollection.find());
};

If you need to do calculated values, there are a couple of ways to approach it.

Approach #1: Change the collection on the client

Pros: easy and fast to develop

Cons: client browser has to do the calculation, which - depending on the collection size and the calculation - could be slow

Example:

var dataWithCalculations = _.map(myCollection.find(), function(document) {
  document.someValue = document.someOtherValue * 2;
  return document;
});
$('#chart').highcharts(dataWithCalculations);

I'm not sure if this approach is reactive or not. If it's not, it should be easy to fix by using a dependency.

Approach #2: Use a transform

Pros: easy and fast to develop

Cons: not reactive

Example:

Forms = new Meteor.Collection("forms", {
 transform: function(document) {
   document.someValue = document.someOtherValue * 2;
   return document;
 }
});

Approach #3: Use a custom publication

Pros: Reactive, calculation run on the server

Cons: Not easy or straightforward

Example: Check the count-by-rooms example in the Meteor documentation

Upvotes: 3

Related Questions