typescript - Angular Ändringsdetektion i en dynamisk komponent
Jag har ett problem med ändringsdetektion i en dynamiskt tillagd komponent i Angular.
Jag har lagt till en länk till en komplett Plunker nedan.
Komponenten har två egenskaper (grid och message), med inställare och hämtare för båda egenskaperna.
Egenskapen grid är baserad på ett "typ"-gränssnitt IGrid, och message är en string. Både grid och message läggs till komponentinstansen när komponenten skapas dynamiskt och läggs till föräldrakomponenten.
Setters för både grid och message kallar på en funktion som heter consolelog.
Baserat på förändringar i deras respektive indata verkar ändringsdetektering för både grid och message fungera.
Problemet jag har är att consolelog-funktionen kallas korrekt i message-setter, men consolelog-funktionen kallas inte korrekt i grid-setter.
Mall :
<div>
<div><b>grid.pinnedColumnHeaders</b></div>
input:
<input type="checkbox"
name="grid.pinnedColumnHeaders"
[(ngModel)]="grid.pinnedColumnHeaders">
</div>
<div>
value: {{ grid.pinnedColumnHeaders || '[blank]' }}
</div>
<hr>
<div>
<div><b>message:</b></div>
input: <input type="text" name="message"
[(ngModel)]="message">
</div>
<div>
value: {{ message || '[blank]' }}
</div>
Komponent :
@Component({
selector: 'app-change-detection-onpush',
template: `...`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChangeDetectionOnPushComponent implements IPage {
private _message: string;
private _grid: IGrid;
ngAfterViewInit() {
}
constructor(private cdRef: ChangeDetectorRef) { }
set grid(val: string) {
this.cdRef.markForCheck();
this.logconsole();
this._grid = val;
}
get grid() {
return this._grid;
}
set message(val: string) {
this.cdRef.markForCheck();
this.logconsole();
this._message = val;
}
get message() {
return this._message;
}
logconsole(){
console.log('test');
}
}
Fullständig Plunker: https://next.plnkr.co/edit/t1xK698tsJDnzS5E?open=lib%2Fapp.ts&deferRun=1
Svar #1
Enligt vad du skrev i kommentarerna har jag två gissningar till om det tillvägagångssätt du antagligen letar efter:
- Är @ngrx/store-metoden. (det är väl dokumenterat)
Är att göra
gridsom en privatSubject(eller BehaviorSubject från 'rxjs') i din tjänst, och skapa setter och getter i tjänsten.import { Injectable } from '@angular/core'; import { Subject } from 'rxjs'; @Injectable() export class MyService{ private grid: Subject<IGrid> = new Subject<IGrid>(); getGrid(): Observable<IGrid> { return this.grid.asObservable(); }; setGrid(values: IGrid): void { this.grid.next(values); } }sedan i någon av dina komponenter (notera, glöm inte att göra
unsubscribepå ngOnDestroy()):export class MyComponent { grid: IGrid; constructor(private service: Myservice){} getGrid(): void { this.service.getGrid().subscribe((grid: IGrid) => this.grid = grid); } setGrid(gridData: IGrid): void { this.service.setGrid(gridData); } }
Ändå måste du i detta tillvägagångssätt hantera inmatningsändring som föreslagits ovan eftersom ngModel inte kommer att kalla på settern om endast en del av ett objekt har ändrats. Men i detta fall kan du vara säker på att om du gör ändringar på ett ställe kommer alla prenumeranter att ta emot ändringarna.
