Richard
Richard

Reputation: 65510

JavaScript scope: access variable inside event handler?

I have the following code. It draws a stacked graph in D3, and then allows the user to filter the lines that are shown, by selecting an option from a drop-down list.

However, I'm having problems with the scope. When I use the dropdown, the console statement shows that series 1 has updated correctly. But series 2, inside the mousemove code, has not updated.

I guess that's because it's bound and has not updated when the variable updates. How can I get access to the updated variable?

 d3.csv("/data/test.csv", function(error, data) {

  function updateGraph(label) {

    // Filter the data. 
    var series = data.filter(function(d, i) {
      return d.Type == label;
    });
    console.log('series 1', series); // This updates correctly. 

    // Draw the paths. 
    var items = svg.selectAll("path").data(newSeries);
    items.enter().append('path').attr("d", function(d) {
      return area(d.data);
    }).on("mousemove", function(d, i) {
      console.log('series 2', series); // This is out of date. 
    });
  }

  // Draw the initial graph. 
  updateGraph('initial');
  // When the user changes the drop-down, redraw the graph. 
  d3.select("#chooseoption").on("change", function(val) {
    updateGraph(this.options[this.selectedIndex].value);
  });

});

Upvotes: 0

Views: 995

Answers (1)

jfriend00
jfriend00

Reputation: 707158

If you want there to be a single series variable that multiple event handlers can access or modify, then you need to define that variable at a scope above all the event handlers that want to participate so they all share access to the same variable rather than multiple copies of the variable exist in multiple closures.

In this case, you could do it like this:

d3.csv("/data/test.csv", function(error, data) {

  // define series variable where multiple event handlers can share it
  var series;
  function updateGraph(label) {

    // Filter the data. 
    series = data.filter(function(d, i) {
      return d.Type == label;
    });
    console.log('series 1', series); // This updates correctly. 

    // Draw the paths. 
    var items = svg.selectAll("path").data(newSeries);
    items.enter().append('path').attr("d", function(d) {
      return area(d.data);
    }).on("mousemove", function(d, i) {
      console.log('series 2', series); // This is out of date. 
    });
  }

  // Draw the initial graph. 
  updateGraph('initial');
  // When the user changes the drop-down, redraw the graph. 
  d3.select("#chooseoption").on("change", function(val) {
    updateGraph(this.options[this.selectedIndex].value);
  });

});

Upvotes: 2

Related Questions