How to provide 'this' context, which points to an Angular 6 component instance?

923 Views Asked by At

I have a working demo with Earth globe, based on D3 and JS. Now I'm trying to create an Angular 6 component out of it.

Here is full demo without Angular:

import * as d3 from 'd3v4';

import { Component, AfterContentInit, ViewEncapsulation } from '@angular/core';

@Component({
  selector: 'earth-globe',
  templateUrl: './earth-globe.component.html',
  styleUrls: ['./earth-globe.component.css'],
  encapsulation: ViewEncapsulation.None
})
export class EarthGlobeComponent implements AfterContentInit {
  private canvas;
  getCountry(c) {
    console.log('Country is: ', c);
  }

  mousemove() {
    console.log('mousemove()::this==', this); // now 'this' points to canvas, which is CORRECT
    // console.log('globe==', globe);
    console.log('ev==', event); // but I also need event
    const c = this.getCountry(this); // and acces to this.getCountry
  }


  ngAfterContentInit() {
    this.canvas = d3.select('#globe');
    this.canvas
      .on('mousemove', this.mousemove)
  }
}

http://jsfiddle.net/up715k2n/

Here is simplified Angular component demo:

https://stackblitz.com/edit/angular-dohwvt

If you move a mouse, the app will console.log 'this'. And in both demos I have 'this' pointing to the canvas, which is correct.

But in Angular example the app has an error:

this.getCountry is not a function

because 'getCountry' is a component method, not canvas.

So, I'm trying to find the way to get both contexts - canvas and component.

How to do it?

https://stackblitz.com/edit/angular-rlttwv?file=src/app/earth-globe.component.ts - points to the component

https://stackblitz.com/edit/angular-xjahkl?file=src/app/earth-globe.component.ts - points to the canvas

1

There are 1 best solutions below

2
On

You could use next syntax (it's not part of standart, but supports with babel )

  // instead of mouse() {
  mousemove = () => {
    console.log('mousemove()::canvas==', this.canvas); // <-- canvas
    console.log('component==', this); // <-- component
    console.log('ev==', event);
    const c = this.getCountry(this);
  }

it would bind the context inside the method

old style fix instead of this would be

  ngAfterContentInit() {
    this.canvas = d3.select('#globe');
    this.canvas
      .on('mousemove', this.mousemove.bind(this)) // <-- changes is .bind(this)
  }

https://javascriptweblog.wordpress.com/2015/11/02/of-classes-and-arrow-functions-a-cautionary-tale/