Search code examples
javascriptclassd3.jsforce-layout

Why is my method not recognizing my object member?


I am trying to create a "generic" class for a D3 force graph. When the graphTick() function is called (or any other method it seems...) the member values of the class are undefined as if the method was not bound to that instance.

I wonder if I'm misunderstanding the JS way of writing a class (I'm from a C++ background) or if I'm misusing the D3 framework. Maybe both?

I've tried to replace....

simulation.on("tick", this.graphTick)

...by:

simulation.on("tick", function(){ 
    /*graphTick implementation*/ 
})

But then it looked like it was called by some anomymous object from D3, so I'm thinking my problem is probably more about JS syntax.

Got a Codepen setup with this class and a quick test: https://codepen.io/mrelemental/pen/VGLNLa


Solution

  • You're using a JavaScript class, which is quite uncommon in D3 codes. There is no problem in using classes per se, but you have to take extra care when dealing with the this keyword.

    The issue in your code is the value of this inside the graphTick function: in the "tick" listener, this is the simulation itself. According to the API:

    When a specified event is dispatched, each listener will be invoked with the this context as the simulation.

    You can easily see it by yourself if you do a console.log(this) inside the function. You'll get:

    {tick: function, restart: function, stop: function, nodes: function, etc...} 
    

    And that explains why both your attempts didn't work: in both of them, this is the simulation itself.

    The solution is simple, just pass the correct this to the graphTick function:

    simulation.on("tick", this.graphTick.bind(this))
    

    Here you can find more information about bind(): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind

    And here is the updated code: https://codepen.io/anon/pen/qgpxNX?editors=0010