I'm dealing with a challenging setup where:
The Parent Service (A) is imported in the Parent Component (B). Then, the Parent Component passes an array of Objects to a Child Component (C), which are referenced from the Parent Service (e.g. <child-component [input]="A.x">, where A.x = [{a},{b},...]).
This setup is rigid and cannot be changed easily because we've abstracted certain parts of our app for reusability in other tools.
Typically, change detection doesn't work properly in this scenario. Workarounds like x = [...x] or x=[]; x=dataArray; don't work with this particular array of objects (Esri ArcGIS Graphic objects). Even lodash cloneDeep fails to solve the issue.
I have tried various approaches:
- Using the usual x = [...x] method.
- Setting x=[] then x=data.
- Experimenting with lodash clone and cloneDeep (cloneDeep doesn't work).
- Implementing @Input() set function along with @Input x: Graphics[] = [];
- Passing a BehaviorSubject and sending data via subject.next(x), but it only triggers the first time.
The initial transition from an empty array to a populated one works fine. The problem arises when trying to filter this array.
I'm running out of ideas on how to tackle this within the limitations of the parent component/service structure. If anyone has suggestions or would like to see more detailed code, I'm willing to provide as much information as possible.
Here's a snippet of the Parent Component (HTML):
<app-gs-arcgis [basemap]="'hybrid'" [graphics]="estateDataDashboardSvc.dashGraphic" [graphicsSubject]="estateDataDashboardSvc.dashGraphicSubject" (clickedPoints)="displayTooltip($event)" [(center)]="center" [(zoom)]="zoom" [padding]="arcgisPadding" [filterEvent]="estateDashboardFiltersSvc.filterEvent" class="absolute w-full h-full"></app-gs-arcgis>
Corresponding code from the Parent Service (TS):
dashGraphic: Graphic[] = [];
dashGraphicSubject: Subject<Graphic[]> = new Subject<Graphic[]>();
...
this.dashGraphic = [];
const graphics: Graphic[] = [];
point.forEach((d, i) => {
const graphic = new Graphic({
geometry : d as any,
symbol : symbol[i],
attributes: {
data: d
}
});
graphics.push(graphic);
});
this.dashGraphic = graphics;
this.dashGraphicSubject.next(this.dashGraphic);
Snippet from the Child Component (TS):
@Input() graphicsSubject = new Subject<Graphic[]>();
...
private _graphics: Graphic[] | null = [];
get graphics(): Graphic[] | null {
return this._graphics;
}
@Input()
set graphics(graphics: Graphic[] | null) {
console.log('Graphics received', graphics);
this._graphics = graphics;
this.rebuildGraphics();
}
...
ngOnInit() {
...
this.graphicsSubject.subscribe(next => {
console.log(next);
this.graphics = next;
});
}