0

I am using d3 and react to create charts. Clicking a button will update the chart. In the component for the chart is an onclick event listener, however the "this" keeps getting mixed up

One method with arrow functions returns Uncaught TypeError: node.getAttribute is not a function:

 this.setupButtons= function() {
          d3.select('#toolbar')
            .selectAll('.buttons')
            .on('click',  ()=> {
              d3.selectAll('.buttons').classed('active', false);
              var button = d3.select(this);

              button.classed('active', true);

              var buttonId = button.attr('id');

                this.toggleDisplay(buttonId)
            });
        }
*/

This is of course because the this refers to the component instance. So I researched how to refer to the click event and found that using e or event.target is supposed to solve the issue. In react, however, an error is returned: Uncaught TypeError: Cannot read property 'target' of undefined

 this.setupButtons= function() {
              d3.select('#toolbar')
                .selectAll('.buttons')
                .on('click',  (e)=> {
                  d3.selectAll('.buttons').classed('active', false);
                  var button = d3.select(e.target);

                  button.classed('active', true);

                  var buttonId = button.attr('id');


                    this.toggleDisplay(buttonId)
                });
            }

Both this.setupButtons and this.toggleDisplay() are defined in the same method, which belongs to a component.

EDIT: This question does not appear to be a "duplicate" of the question provided.This was an issue of D3's handling of event, not the use of this, apparently. The solution to this question (add d3.event.target instead of event.target) is not provided as an answer in the question this supposedly duplicates.

auto
  • 1,062
  • 2
  • 17
  • 41
  • 1
    Just use a regular function instead of an arrow function. jQuery can't provide a thisArg to arrow functions since arrow functions don't have their own `this`. – Paul Aug 13 '19 at 03:33
  • I need to refer to the the click event in `var button = d3.select(e.target);` Then I need to call `this.toggleDisplay(buttonId)` which is another function that uses the component's `this` – auto Aug 13 '19 at 03:37
  • `e.target` should work. I don't really understand why `e` would ever be `undefined` there. I don't know React though. – Paul Aug 13 '19 at 03:56
  • `d3` goes about things a bit differently. The event is accessed from `d3` itself (`d3.event`). https://octoperf.com/blog/2018/04/17/d3-js-mouse-events-and-transitions-tutorial/#how-to-use-d3-event-object To be honest, I'm not sure how this translates into helping you in this case, but at least you won't be debugging what is normally expected of a regular `Event`. – Ezra Aug 13 '19 at 03:59
  • @Ezra, can you make this an official answer? This seems to work for me. Thank you. Though I don't know what you mean by ` To be honest, I'm not sure how this translates into helping you in this case` – auto Aug 13 '19 at 04:49

3 Answers3

0

You can store the reference of the outer this into another variable. I generally store it into a variable like var that = this and then you can reference the variable that wherever required.

this.setupButtons= function() {
          var that = this;
          d3.select('#toolbar')
            .selectAll('.buttons')
            .on('click',  ()=> {
              d3.selectAll('.buttons').classed('active', false);
              var button = d3.select(that);

              button.classed('active', true);

              var buttonId = button.attr('id');

                that.toggleDisplay(buttonId)
            });
        }
Molly
  • 1,887
  • 3
  • 17
  • 34
0

d3 goes about things a bit differently. The event is accessed from d3 itself (d3.event).

Source: https://octoperf.com/blog/2018/04/17/d3-js-mouse-events-and-transitions-tutorial/#how-to-use-d3-event-object

Ezra
  • 1,118
  • 9
  • 13
-1

Assign var that = this in the outer function. Now you have a way to reference the outer this.

this.setupButtons = function () {
    var that = this;
    d3.select('#toolbar')
        .selectAll('.buttons')
        .on('click', function() {
            d3.selectAll('.buttons').classed('active', false);
            var button = d3.select(this);

            button.classed('active', true);

            var buttonId = button.attr('id');

            that.toggleDisplay(buttonId)
        });
}
Dafang Cao
  • 897
  • 5
  • 15