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.