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

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

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.

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]
    ];
  }

Any more thoughts about this?

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

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?

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}}
        },
	    {[...]}
    ];
}

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

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

1 Like

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