7

I know that 'this' in JavaScript has a different meaning than in in TypeScript, as per this article 'this' in TypeScript. I have the following code in JavaScript used to create a thicker stroke on the selected node, and give all other nodes a smaller stroke.

node.on('click', function (d) {
   d3.selectAll('circle').attr('stroke-width', 1.5);
   d3.select(this).select('circle').attr('stroke-width', 5);
})

In TypeScript I have

this.node.on('click', (d:any) => {
   this.node.selectAll('circle').attr('stroke-width', 1.5);
   [this is where I need help].select('circle').attr('stroke-width', 5);
}
Aluan Haddad
  • 29,886
  • 8
  • 72
  • 84
H. Trujillo
  • 427
  • 1
  • 8
  • 21
  • 1
    Why do you want it? Just use first snippet it's perfectly fine, you don't need arrow function syntax. – dfsq Apr 21 '17 at 19:19
  • Because 'this' doesn't mean the same in JavaScript than it does in TypeScript and I'm trying to find the "correct" way of achieving the JavaScript code for an Angular 2 application. – H. Trujillo Apr 21 '17 at 19:21
  • 1
    `this` has absolutely the same meaning an behavior in TS and JS. Would be interesting to see more code. It's strange that you use `this.node` as a replacement for `d3` and for `node` simultaneously. Is it correct in your case? – dfsq Apr 21 '17 at 19:32
  • @H.Trujillo That's not what that article says. It says that in JavaScript, as well as in TypeScript, `this` behaves differently from **other** languages. – artem Apr 21 '17 at 19:36
  • @dfsq I rewrote that line differently when I was rewriting the code, but d3.selectAll would do the same thing. So there's no issue with that line, the issue I have is with the line that follows. – H. Trujillo Apr 21 '17 at 19:47
  • @dfsq my understanding is that 'this' in the JS block refers to the node, this in the TS refers to the class it is in. export class Grapher { this.node.on('click', (d:any) => { **this**...} } In TS, 'this' refers to 'Grapher' – H. Trujillo Apr 21 '17 at 19:49
  • @artem you're right, I misunderstood that, however I still understand there's a difference in what 'this' means in the context of the block of code – H. Trujillo Apr 21 '17 at 19:53
  • Explore `d` object, maybe it has reference to node, same as `this` in the first snippet. – dfsq Apr 21 '17 at 22:09
  • 1
    @dfsq unfortunately it's not possible to get the DOM element just using the `d` object (the first argument). However, the second and third arguments can be easily used to get `this` (which in D3 methods is the current DOM element). – Gerardo Furtado Apr 22 '17 at 09:31

3 Answers3

17

As already stated in this comment and this answer, this does not have a different meaning between JavaScript and TypeScript.

That being said, your problem here is way more prosaic: you're trying to use this in an arrow function to get the current DOM element, and that will simply not work.

So, in a nutshell, the problem here is the difference of this between an arrow function and a regular function, not between TypeScript and JavaScript.

Solution

There is an alternative to this, described everywhere in the API: when you use an anonymous function in most of D3 methods, the arguments being passed are...

... the current datum (d), the current index (i), and the current group (nodes), with this as the current DOM element (nodes[i]).

Thus, this is simply the current index (the second argument) of the nodes groups (the third argument).

So, in the snippet below:

selection.on("foo", function (d, i, n){
    console.log(this)
    console.log(n[i])
})

The two console.log will return the same thing.

As you are using an arrow function, the solution is (in JavaScript):

this.nodes.on("click", (d, i, n) => {
    d3.select(n[i])//rest of your code here
})

If you want to read more about the use of the second and the third arguments to get the DOM element, have a look at this example: d3 v4 retrieve drag DOM target from drag callback when `this` is not available

Graham
  • 7,431
  • 18
  • 59
  • 84
Gerardo Furtado
  • 100,839
  • 9
  • 121
  • 171
  • 1
    _Regardless the issue of this being different between JavaScript and TypeScrip (which I doubt)_ I just want to say that you doubt correctly. That claim made in the OP is 100% false. There **no** difference between their behavior whatsoever. – Aluan Haddad Apr 22 '17 at 08:59
  • 1
    @AluanHaddad Thanks for saying that. As I never used TypeScript I didn't want to say anything with certainty, but yes, since TypeScript compiles to plain JavaScript that claim makes no sense. – Gerardo Furtado Apr 22 '17 at 09:10
  • 2
    Right its not so much about it compiling to JavaScript actually. For example so does Dart, but Dart does treat `this` differently. It is about TypeScript being a _superset_ of JavaScript. That is the definition of the language. That means all JavaScript constructs have the same meaning, not in the compiled output, but at source level. – Aluan Haddad Apr 22 '17 at 09:13
1

The premise of this question, How to translate 'this' in D3 JavaScript to TypeScript?, is false. I did not downvote because it is important to educate.

I just want to clarify that this is 100% identical in TypeScript and JavaScript

In fact, all TypeScript syntax that is also valid JavaScript syntax has the exact same semantics.

This is what makes TypeScript a superset of JavaScript.

Update: I actually will amend this with an answer because the problem was that you thought the meaning was different. You are confused about arrow function syntax

(params) => expression or block

First of all => is not a TypeScript feature, but a JavaScript feature.

Secondly, TypeScript, as noted above naturally support both forms. This means that no translation is needed.

this means the same thing in TypeScript as it does in JavaScript.

In both languages it means something different in the context of => than it does in the context of function. There are many, many answers explaining this on SO, so I won't repeat them.

So here is the answer to this question.

If you have this file:

d3-app.js

node.on('click', function (d) {
  d3.selectAll('circle').attr('stroke-width', 1.5);
  d3.select(this).select('circle').attr('stroke-width', 5);
});

It works and you want to rewrite it in TypeScript.

Here is what you do:

  1. rename d3-app.js to d3-app.ts

That is all.

Gerardo Furtado
  • 100,839
  • 9
  • 121
  • 171
Aluan Haddad
  • 29,886
  • 8
  • 72
  • 84
-2

The answer was to replace 'this' with 'd3.event.currentTarget'

d3.select(d3.event.currentTarget).select('circle').attr('stroke-width', 5);
H. Trujillo
  • 427
  • 1
  • 8
  • 21