0

I have a child component that receives an input observable as typed array via async pipe from parent component. The child component has multiple properties and methods that are initiated by this input property. These properties appear initiated properly in two methods, but not so in another - hence throwing an 'undefined' error.

I am relatively new to software development, so any additional context in response is welcome!

parent.component.ts

data$: Observable < dataType[] > = this.store.select(selectUIData);
data: dataType[] = [];

ngOnInit(): void {
    this.data$.subscribe({
        next: (d) => {
            this.data = d;
        },
        error: (e) => console.error(e)
    });
}

parent.component.html

<app-child [data]='data'></app-child>

child.component.ts

@ViewChild('chart') private chartContainer ? : ElementRef;

xScale: any = d3.scaleLinear().range([0, n1]);
yScale: any = d3.scaleBand().range([n2, 0]);
yScale2: any = d3.scaleBand().range([n2, 0]);
brush: any;
context: any;
svg: any;
...more props

workingFunction(data: dataType[]) {
    this.svg = d3.select(this.chartContainer?.nativeElement).append('svg');
    this.xScale.domain([0, d3.max(data, d => d.numProp)]);
    this.yScale.domain(data.map(d => d.stringProp));
    this.yScale2.domain(this.yScale.domain());
    console.log(this.yScale); //prints a function object 

    this.brush = d3.brushY().chainedMethods().on('brush end', this.brushed);

    this.context = this.svg.append('g').chainedMethods();

    ...more code
}

workingFunction2(data: dataType[]) {

    this.context.append('g').chainedMethods()
        .call(this.brush).call(this.brush.move, this.yScale.range());

    ...more code
}

brushed(e: any) {
    var s = e.selection || this.yScale.range();
    console.log('brushed', this.yScale); //yScale is undefined

    this.yScale.domain(s.map(this.yScale2.invert, this.yScale2)); //error is here

}

clickEvent() {
    this.workingfunction1(this.data);
    this.workingfunction2(this.data);
}

child.component.html

<button (click)="clickEvent()>Click Me!</button>
<div #chart> </div>

While I understand that this problem can be circumnavigated by converting the brushed function into an arrow function like so - brushed = (e: any) => { ...code }, and also possibly by implementing an Angular resolver. But I would still love to learn why my aforementioned approach broke.

I expected that 'yScale' would be defined inside 'brushed' method, since it was defined inside the two 'workingFunction' methods. I also expected 'yScale' to always be defined since its initialized without any dependence on the input Data.

p.s. I am aware that .invert method does not work on a band scale. I am working on that separately.

VLAZ
  • 26,331
  • 9
  • 49
  • 67
  • Does this answer your question? [How to access the correct \`this\` inside a callback](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback) and [How does the "this" keyword work, and when should it be used?](https://stackoverflow.com/q/3127429) – VLAZ Aug 31 '23 at 05:24
  • You pass a method reference in `on('brush end', this.brushed);` thus when it gets called it does not have the correct value for `this`. – VLAZ Aug 31 '23 at 05:25
  • @VLAZ I am still not sure. `on( 'brush end', this.brushed);` gets called in `workingFunction` whose `this` should still be the component's `this`. I'm saying this because `workingFunction` contains a number of other props that are resolved correctly. – Kazi Ahmed Aug 31 '23 at 05:59
  • Doesn't matter. When the method reference is called ***AT THAT POINT*** is the value of `this` determined based on how the call is made. The call doesn't implicitly pass a value for `this`. https://jsbin.com/zesocokubo/1/edit – VLAZ Aug 31 '23 at 06:01
  • Arrow functions worked. But I'm also not sure whether I should rename `this` to `self` in the component, and pass `self.brushed`. Same question about binding `this`. Do I do the binding at the tail-end of that method reference, as in - `on( 'brush end', this.brushed).bind(this);`? – Kazi Ahmed Aug 31 '23 at 06:04

0 Answers0