0

I have a web page with multiple Google Charts.

Underneath each chart I'd like to add a button:

enter image description here

When a button is clicked, then a table featuring same data should be shown or hidden underneath it.

Displaying charts, buttons, tables works fine for me.

And they have ids: ..._chart, ..._button, ..._table.

However getting the click handler to toggle a table doesn't work and the console.log in the code below always prints the same id string.

I suspect it is a function closure issue, but I'm not sure how to workaround it.

Here is my faulty code:

function drawCharts() {
        for (var csv in data) {
                ......skipped some code...

                var chart = new google.visualization.LineChart(document.getElementById(csv + '_chart'));
                chart.draw(t, options);

                var table = new google.visualization.Table(document.getElementById(csv + '_table'));
                table.draw(t, options);

                $('#' + csv + '_table').hide();

                $('#' + csv + '_button').click(function() {
                        console.log('#' + csv + '_table'); // ALWAYS PRINTS SAME
                        $('#' + csv + '_table').toggle();
                });
        }
}

$(function() {
        google.setOnLoadCallback(drawCharts);
});

Any help please?

Alexander Farber
  • 21,519
  • 75
  • 241
  • 416
  • 1
    Classic for loop scope issue. Each iteration of the for loop uses the exact same scope, therefore, by the end, all click events will be looking at the same `csv` variable, and since it can only contain one value, it'l contain the value of the last one every time. You can solve this using an IIFE, or by using an iterating function that generates a new scope for each iteration, such as $.each – Kevin B Jun 27 '13 at 15:35
  • 1
    Well `cvs` is the same variable for all callbacks, thats why they are the same and how closure/scopes work in `js`. What you could do is to use ` $('#' + csv + '_table').data("csv",cvs);` and retrive it again in the callback with `$(this).data("csv")`. – t.niese Jun 27 '13 at 15:37

1 Answers1

1

Wrap your click handler setup inside a closure

(function(csv){
    $('#' + csv + '_button').click(function(x) {
        console.log('#' + csv + '_table'); 
        $('#' + csv + '_table').toggle();
    });
})(csv);
Ally
  • 4,894
  • 8
  • 37
  • 45
  • `(function(csv){return csv;})(csv);` that does not really make sense if it is place above the click handler, because you invoke the function right at the creating and assigning it to `csv2` but `var csv2` is still bound to the scope of the function (there are no block level scopes), so you will have the same problem. – t.niese Jun 27 '13 at 15:41
  • I hear what you're saying, it's a snippet I use a lot, possibly not applicable here, I haven't tested. But wrapping the whole thing in a closure is fool proof. I've removed the other option for now. – Ally Jun 27 '13 at 15:43
  • The second (remaining) part is fine. But `var csv2 = (function(csv){return csv;})(csv);` makes no sense this way, because it is the same as writing `var csv2=csv;`. If you use this you should check if your code is really working. – t.niese Jun 27 '13 at 15:45
  • Yeah you're right, I've used that snippet for something before, can't think of a use case now, so maybe it was in error. – Ally Jun 28 '13 at 08:23