Getting array data from helper function into a non-helper function


#1

I have a difficult (for me) problem to solve and am hoping there is a simple solution - there should be as what I am attempting seems pretty doable.

I have a meteor app in which a template uses both template helpers and javascript within the template itself via tags. The reason I am doing this is that I have a d3 chart that will not work as a template helper and must be in the <script> tag.

The d3 chart uses several arrays, returned from a function that looks like this (in the template, tabs.html):

function simulatedTestData() {
    return [
      {
         key: "Pressure (hPa)",
           values: [
             [1498706100000, 1017.2],
             [1498792500000, 1016.6],
      	     [1498878900000, 1014.1],
	         [...]
           ]
      },
      {[...]}
   ];
}

In all there are five arrays that contain atmospheric data for a given date.

Everything works fine as is, but of course I do not want static arrays, I want to be able to retrieve the data from mogodb which will result in dynamic arrays of variable length.

I am attemping to pass an array (still test data, no mongodb yet) from a helper function to the simulatedTestData() in the template <script> tag, with mixed results.

Here is the helper function in tabs.js containing a single array (it should look familiar):

getData: function() {
    return [
      [1496373300000, 1015.7],
      [1496459700000, 1014.3],
      [1496546100000, 1016.2],
      [...]
    ];
}

Now, in the template (tabs.html), I am attmempting the following call from the same function as before, but with the the data coming from the template helper:

function simulatedTestData() {
    var len = {{getData.length}}
    console.log(len); //30

    var i = 0;
    return [
       {
           key: "Pressure (hPa)",
           values: [
              [{{getData}}]
            ]
        },
	    {[...]}
    ];
}

This results in only the first element of the array getting passed to the d3 chart instead of the entire thing.

However, if I do the following in the template html code:

<div id="chart1">
    {{getData}}
</div>

I get the full array written to the div, but of course not in the chart.

I know I can get each element by index, but that will not work with the dynamic nature of the final array.

I’ve also attempted to loop through (note the ‘var i = 0;’ line above):
{{getData.[@i]}} but that causes d3 to go into spasms of “cannot get property '0' of unknown” and not a good solution in any case.

So, how can I get the entire array into values[]?

Thx,

-k


#2

I think it would be helpful to see your template code as a whole instead of the bits and pieces as it’s a bit hard to reason about what exactly you’re trying to accomplish.


#3

This is the template:

<template name="tab2">
  <div class="container2">
    <header>
      <h1>History</h1>
    </header>

    <div class="graph">
      <div id="chart1">
        <!-- {{getData}} --> <!-- when not commented, this writes the full array data to the document -->
      </div>

      <script>
        var chart;
        var data;
        var legendPosition = "top";

        var toggleLegend = function() {
          if (legendPosition == "top") {
              legendPosition = "bottom";
          } else {
              legendPosition = "top";
          }
          chart.legendPosition(legendPosition);
          chart.update();
        };

        nv.addGraph(function() {
          chart = nv.models.lineChart()
            .options({
              duration: 300,
              useInteractiveGuideline: true
            });

          // get x,y data from array in simulatedTestData()
          chart.x(function(d) {
            return d[0];
          })

          chart.y(function(d) {
            return d[1];
          })

          // chart sub-models (ie. xAxis, yAxis, etc) when accessed directly, return themselves, not the parent chart, so need to chain separately
          chart.xAxis
            .axisLabel('Date')
            .staggerLabels(false)
            .tickFormat(function(d) {
              if (d == null) {
                return 'N/A';
              }
              return d3.time.format('%m/%d/%y')(new Date(d));
            });

          chart.yAxis
            .axisLabel('Value')
            .tickFormat(function(d) {
              if (d == null) {
                return 'N/A';
              }

              return d3.format(',.0f')(d);
            });

          data = simulatedTestData();

          d3.select('#chart1').append('svg')
            .datum(data)
            .call(chart);

          nv.utils.windowResize(chart.update);

          return chart;
        });

        function simulatedTestData() {
          var len = {{getData.length}}
          console.log(len); // gives length of array I am passing in and is accurate

          var i = 0;
          return [
            {
              key: "Pressure (hPa)",
              values: [
                [{{getData}}] // this was a literal array, but I want it to be a variable so I can pass in a dynamic, variable-length array, but unfortunately only getData[0] is passed to the chart. See helper function below.
              ]
            },
            {
              key: "Humidity (%)", // literal array. This works
              values: [
                [1496373300000, 67],
                [1496459700000, 63],
                [1496546100000, 63],
                [1496632500000, 46],
                [1496718900000, 28],
                [1496805300000, 48],
                [1496891700000, 51],
                [1496978100000, 62],
                [1497064500000, 58],
                [1497150900000, 74],
                [1497237300000, 60],
                [1497323700000, 75],
                [1497410100000, 51],
                [1497496500000, 52],
                [1497582900000, 93],
                [1497669300000, 67],
                [1497755700000, 52],
                [1497842100000, 62],
                [1497928500000, 54],
                [1498014900000, 65],
                [1498101300000, 52],
                [1498187700000, 24],
                [1498274100000, 31],
                [1498360500000, 20],
                [1498446900000, 41],
                [1498533300000, 54],
                [1498619700000, 48],
                [1498706100000, 61],
                [1498792500000, 40],
                [1498878900000, 57]
              ]
            },
            {
              key: "Temperature (°C)",
              values: [
                [1496373300000, 16],
                [1496459700000, 20],
                [1496546100000, 17],
                [1496632500000, 17],
                [1496718900000, 24],
                [1496805300000, 22],
                [1496891700000, 22],
                [1496978100000, 14],
                [1497064500000, 14],
                [1497150900000, 14],
                [1497237300000, 17],
                [1497323700000, 13],
                [1497410100000, 16],
                [1497496500000, 18],
                [1497582900000, 16],
                [1497669300000, 17],
                [1497755700000, 20],
                [1497842100000, 25],
                [1497928500000, 26],
                [1498014900000, 18],
                [1498101300000, 20],
                [1498187700000, 24],
                [1498274100000, 28],
                [1498360500000, 33],
                [1498446900000, 28],
                [1498533300000, 20],
                [1498619700000, 13],
                [1498706100000, 19],
                [1498792500000, 26],
                [1498878900000, 23]
              ]
            },
            {
              key: "Blob Count",
              values: [
                [1496373300000, 9],
                [1496459700000, 9],
                [1496546100000, 4],
                [1496632500000, 6],
                [1496718900000, 7],
                [1496805300000, 7],
                [1496891700000, 3],
                [1496978100000, 4],
                [1497064500000, 8],
                [1497150900000, 6],
                [1497237300000, 7],
                [1497323700000, 9],
                [1497410100000, 9],
                [1497496500000, 5],
                [1497582900000, 8],
                [1497669300000, 7],
                [1497755700000, 6],
                [1497842100000, 7],
                [1497928500000, 6],
                [1498014900000, 5],
                [1498101300000, 6],
                [1498187700000, 8],
                [1498274100000, 6],
                [1498360500000, 5],
                [1498446900000, 8],
                [1498533300000, 7],
                [1498619700000, 6],
                [1498706100000, 5],
                [1498792500000, 9],
                [1498878900000, 9]
              ]
            },
            {
              key: "Moth Count",
              values: [
                [1496373300000, 1],
                [1496459700000, 2],
                [1496546100000, 0],
                [1496632500000, 5],
                [1496718900000, 4],
                [1496805300000, 7],
                [1496891700000, 3],
                [1496978100000, 1],
                [1497064500000, 8],
                [1497150900000, 0],
                [1497237300000, 6],
                [1497323700000, 9],
                [1497410100000, 5],
                [1497496500000, 2],
                [1497582900000, 6],
                [1497669300000, 7],
                [1497755700000, 0],
                [1497842100000, 7],
                [1497928500000, 6],
                [1498014900000, 5],
                [1498101300000, 6],
                [1498187700000, 3],
                [1498274100000, 6],
                [1498360500000, 5],
                [1498446900000, 8],
                [1498533300000, 6],
                [1498619700000, 6],
                [1498706100000, 2],
                [1498792500000, 9],
                [1498878900000, 9]
              ]
            }
          ];
        }
      </script>
    </div>
  </div>
</template>

The helper function. Eventually, this array will be populated by mongodb queries, and will be of variable length:

getData: function() {
    return [
      [1496373300000, 1015.7],
      [1496459700000, 1014.3],
      [1496546100000, 1016.2],
      [1496632500000, 1020.3],
      [1496718900000, 1014.8],
      [1496805300000, 1011.8],
      [1496891700000, 1005.4],
      [1496978100000, 1014.8],
      [1497064500000, 1011.4],
      [1497150900000, 1012.9],
      [1497237300000, 1015.2],
      [1497323700000, 1020.6],
      [1497410100000, 1019.9],
      [1497496500000, 1017.3],
      [1497582900000, 1013.9],
      [1497669300000, 1019.4],
      [1497755700000, 1019.6],
      [1497842100000, 1016.5],
      [1497928500000, 1014.1],
      [1498014900000, 1021.8],
      [1498101300000, 1022.4],
      [1498187700000, 1019.8],
      [1498274100000, 1016.3],
      [1498360500000, 1012.2],
      [1498446900000, 1010.0],
      [1498533300000, 1014.6],
      [1498619700000, 1013.6],
      [1498706100000, 1017.2],
      [1498792500000, 1016.6],
      [1498878900000, 1014.1]
    ];
  }

#4

Any more thoughts about this?


#5

Meteor’s reactivity and helpers don’t work well with <script> tags, in my experience. I recommend you put the logic in your <script> tag in a helper as well


#6

I would do that, but then I will have issues with getting mongodb data into the <script> code as the minimongo driver is out of context - and I would prefer to avoid the mess of having multiple drivers accessing the db.

I believe the issue is the array itself. Perhaps a formatting issue…

If I look at the arrays, the literal arrays look like this:

1: Object
    key: "Humidity (%)"
    values: Array(30)
        0: Array(2)
            0: 1496373300000
            1: 67
             ...
        1: Array(2)
            0: 1496459700000
            1: 63
            ...
        ...

Whereas the array I am passing in looks like this:

0: Object
    key: "Pressure (hPa)"
    values: Array(60)
        0: 1496373300000
        1: 1015.7
        2: 1496459700000
        3: 1014.3
        ...

So, instead of getting an array of 30 arrays, the inner arrays are being stripped off and I am getting a single array of sixty values.

Any ideas?


#7

Looks like getData already returns an array of tuples, but in your javascript you then nest it in another array? Have you tried

function simulatedTestData() {
    var len = {{getData.length}}
    console.log(len); //30

    var i = 0;
    return [
       {
           key: "Pressure (hPa)",
           values: {{getData}}
        },
	    {[...]}
    ];
}


#8

Yes, I tried that. It results in “Uncaught SyntaxError: Unexpected token ,


#9

I recommend to not use your <script> approach and instead work within the Meteor templating system. Here is an example.


#10

I’ll have a look at that. I was hoping not to have to rewrite the entire thing, but this may be the only path forward.

Thx,

-k