Google图表:在循环中设置多个监听器会覆盖之前的监听器

Google Charts: setting up multiple listeners in a loop overwrites the previous ones

在一个网页上,我展示了我在 for 循环中创建的多个 Google 图表(用户可以 select 他想查看多少个包含不同数据集的图表)。我是这样做的:

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

这按预期工作。 {{ length }} 是一个 Jinja 变量,表示用户想要查看的图表数量,也是包含数据的 <div> id。

我想为每个图表添加一个侦听器,所以我在第一个循环之外添加了另一个 for 循环:

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

在上面的部分中,console.log("Container id: " + chart.container.id); returns Container id: 0, Container id: 1.... 用于定义 {{ length }}.

当用户 select 要查看一张图时({{ length }} = 1),事件侦听器可以正常工作。 当 {{ length }} > 1,因此页面上有多个图表时,事件侦听器出现在所有图表上,但只执行循环中最后创建的图表中的内容。

这是select处理函数:

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
}

在这种情况下,在 console.log("trendsTable"+ myChart.container.id); 中,myChart.container.id 始终是循环中的最后一个,即使我单击上面的图表(应该有 myChart.container.id - 1)也是如此。例如,如果有两个图表,如果我点击第一个,我会得到 trendsTable1 而不是 trendsTable0,如果我点击第二个,我也会得到 trendsTable1

我怀疑我在动态声明事件侦听器时做错了什么。有人有什么建议吗?

谢谢

好的,所以我发现是问题所在。并不是我在循环中声明了事件侦听器,而是我传递给 selectHandler 的数据在每次迭代时都被覆盖了。

This post 帮助我理解了 JS 中的闭包,并帮助我修复了用于创建侦听器的循环:


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);
  }());
}

希望这对其他人有帮助