3

I'm trying to use D3.js event listeners with arrow functions, but it does not seem to work.

this is bind to undefined.

How can I access this using ES6 arrow functions?

ES5:

svg.selectAll('circle')
  .data(data)
  .enter()
  .append('circle')
  .attr('r', '10')
  .attr('cx', (d) => x(d.day))
  .attr('cy', (d) => y(d.amount))
  .on('mouseenter', function (d) {
    console.log(this); // output '<circle r="10" cx="10" cy="1"/>'
  });

ES6 (using arrow function):

svg.selectAll('circle')
  .data(data)
  .enter()
  .append('circle')
  .attr('r', '10')
  .attr('cx', (d) => x(d.day))
  .attr('cy', (d) => y(d.amount))
  .on('mouseenter', (d) => {
    console.log(this); // output: 'undefined'
  });
CuriousSuperhero
  • 6,531
  • 4
  • 27
  • 50
  • 2
    Arrow functions **are not** a replacement for `function`. Nor are they shorthand. They are fundamentally different concepts and are not interchangeable – CodingIntrigue Dec 04 '15 at 10:47
  • 1
    Related: http://stackoverflow.com/questions/32881022/using-arrow-functions-with-d3?rq=1 – Pinguin Dirk Dec 04 '15 at 10:50

1 Answers1

4

This is expected behaviour. (Below is my poor attempt at explaining this behaviour. You're likely better off reading this)

The context (this) in which an arrow function is executed will be the context in which they are defined (What ever this is outside the function)

D3 likely sets the context of your event listener to be the object which is emitting the event (As in your ES5 example).

But, by using arrow functions, you are forcing the context to be bound to the context in which you defined the function. In your case, this context is undefined / window as your code is not contained within another function.

Perhaps it is better explained if I convert your ES6 example back into ES5):

var self = this;    
svg.selectAll('circle')
      .data(data)
      .enter()
      .append('circle')
      .attr('r', '10')
      .attr('cx', (d) => x(d.day))
      .attr('cy', (d) => y(d.amount))
      .on('mouseenter', (d) => {
        console.log(self); // output: 'undefined'
      });

My advice to fix your issue is simple. Use a regular function as your event subscriber (There is also no benefit of using arrow functions for your two 'attr' subscribers).

svg.selectAll('circle')
  .data(data)
  .enter()
  .append('circle')
  .attr('r', '10')
  .attr('cx', (d) => x(d.day))
  .attr('cy', (d) => y(d.amount))
  .on('mouseenter', function(d) {
    console.log(this); // output '<circle r="10" cx="10" cy="1"/>'

  });
Richard Walton
  • 4,789
  • 3
  • 38
  • 49