0

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

alexfrize
  • 1,022
  • 1
  • 16
  • 35

1 Answers1

0

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/

Vasiliy vvscode Vanchuk
  • 7,007
  • 2
  • 21
  • 44
  • This will not work. 'this' will point to the component instance, but lose the 'canvas'. The main issue is that I need both of them. – alexfrize Sep 24 '18 at 18:49
  • `this` could reffer to the only one object. In example above - it would be a component. if you need canvas - use `this.canvas` to get access, check updated code – Vasiliy vvscode Vanchuk Sep 25 '18 at 04:58