0

On a webpage I present multiple Google Charts graph that I create in a for loop (a user can select how many graphs containing different datasets he wants to see). This is how I do it:

google.charts.load('current', {packages: ['corechart']});
google.charts.setOnLoadCallback(drawTable);

var arrayData = new Array();
var arrayChart = new Array();

function drawTable() {

    for (var i = 0; i < {{ length }}; i++) {
        var JSONdata = document.getElementById(i);
        arrayData['data' + i] = new google.visualization.DataTable(JSONdata.innerHTML);
        arrayChart['chart' + i] = new google.visualization.AreaChart(document.getElementById(i));

    var options = {};

    arrayChart['chart' + i].draw(arrayData['data'  + i], options);
}

This works as intended. {{ length }} is a Jinja variable representing the number of graphs a user wants to see and is also the <div> id where the data is contained.

I wanted to add a listener for each graph, so I added another for loop outside the first one:

for (i = 0; i < {{ length }}; i++){
    var chart = arrayChart['chart' + i];
    var data = arrayData['data' + i];

    console.log("Container id: " + chart.container.id);

    google.visualization.events.addListener(chart, 'select', function () {
                                          selectHandler(chart, data);
                                          });
  } 

In the part above, console.log("Container id: " + chart.container.id); returns Container id: 0, Container id: 1.... for the defined {{ length }}.

The event listener correctly works when a user selects one graph to see ( {{ length }} = 1). When {{ length }} > 1, and so there are multiple graphs on the page, the event listener is present on all graphs but only does stuff in the graph last created in the loop.

This is the selectHandler function:

function selectHandler(myChart, myData) {
      // I want to do stuff in tables in different <table> with id=trendsTable + number
      // myChart.container.id is equal to the number in id=trendsTable + number 
      console.log("trendsTable"+ myChart.container.id);
      var table = document.getElementById("trendsTable" + myChart.container.id);
      var tbodyRowCount = table.tBodies[0].rows.length;
      var selectedItem = myChart.getSelection()[0];
      if (selectedItem) {
        var topping = myData.getValue(selectedItem.row, 0);
        alert(topping)
      }
   // Do some more stuff
}

In this case, in console.log("trendsTable"+ myChart.container.id);, myChart.container.id is always the last one in the loop, even if I click on the graph above (which should have myChart.container.id - 1). For example, if there are two graphs, if I click on the first one, I get trendsTable1 instead of trendsTable0 and if I click on the second one, I also get trendsTable1.

I suspect I'm doing something wrong when declaring the event listeners dynamically. Does anyone have some advice?

Thank you

Guillaume
  • 77
  • 8

1 Answers1

0

Alright so I found out was the issue was. It wasn't that I declared the event listeners in a loop, but that the data I passed to the selectHandler was overwritten with every iteration.

This post helped me understand closures within JS, and helped me fixed the loop I used to create the listeners:


for (i = 0; i < {{ length }}; i++){
(function () {
    var chart = arrayChart['chart' + i];
    var data = arrayData['data' + i];

//    console.log("Container id: " + chart.container.id);

    google.visualization.events.addListener(arrayChart['chart' + i], 'select', function () {
                                          selectHandler(chart, data);
                                          }, false);
  }());
}

Hope this helps someone else

Guillaume
  • 77
  • 8