Jak wymusić ponowne renderowanie komponentu w Angular 2? Do celów debugowania, pracując z Redux, chciałbym zmusić komponent do ponownego renderowania widoku, czy to możliwe?
Jak wymusić ponowne renderowanie komponentu w Angular 2? Do celów debugowania, pracując z Redux, chciałbym zmusić komponent do ponownego renderowania widoku, czy to możliwe?
Odpowiedzi:
Renderowanie następuje po wykryciu zmiany. Aby wymusić wykrywanie zmian, aby wartości właściwości komponentów, które uległy zmianie, były propagowane do modelu DOM (a następnie przeglądarka wyrenderuje te zmiany w widoku), oto kilka opcji:
$rootScope.$digest()
- tzn. Sprawdź pełne drzewo komponentów$rootScope.$apply(callback)
- tzn. Ocenia funkcję callback w strefie Angular 2. Myślę, ale nie jestem pewien, czy kończy się to sprawdzaniem pełnego drzewa komponentów po wykonaniu funkcji zwrotnej.$scope.$digest()
- tzn. Sprawdza tylko ten składnik i jego dzieciTrzeba będzie importować, a następnie wstrzyknąć ApplicationRef
, NgZone
albo ChangeDetectorRef
do swojego urządzenia.
W przypadku twojego konkretnego scenariusza zalecałbym ostatnią opcję, jeśli zmienił się tylko jeden komponent.
this is the first time I am facing an update not working in ng2
. Strategia wykrywania zmian jest domyślna, więc wiem, że nie zepsułem strategii wykrywania zmian.
this
kontekstu w wywołaniu zwrotnym POST.
pure:false
w rurze. Działa, ale jest zbyt drogi (nieefektywny) dla mojego przypadku użycia.
tx, znalazłem obejście, którego potrzebowałem:
constructor(private zone:NgZone) {
// enable to for time travel
this.appStore.subscribe((state) => {
this.zone.run(() => {
console.log('enabled time travel');
});
});
Running zone.run wymusi ponowne renderowanie komponentu
Podejście ChangeDetectorRef
import { Component, OnInit, ChangeDetectorRef } from '@angular/core';
export class MyComponent {
constructor(private cdr: ChangeDetectorRef) { }
selected(item: any) {
if (item == 'Department')
this.isDepartment = true;
else
this.isDepartment = false;
this.cdr.detectChanges();
}
}
Wymuszam ponowne załadowanie komponentu za pomocą * ngIf.
Wszystkie komponenty w moim kontenerze wracają do haków pełnego cyklu życia.
W szablonie:
<ng-container *ngIf="_reload">
components here
</ng-container>
Następnie w pliku ts:
public _reload = true;
private reload() {
setTimeout(() => this._reload = false);
setTimeout(() => this._reload = true);
}
setTimeout()
. Teraz mój pracuje z prostym i lekkim rozwiązaniem!
Inne odpowiedzi tutaj zawierają rozwiązania do wyzwalania cykli wykrywania zmian, które aktualizują widok komponentu (co nie jest tym samym, co pełne ponowne renderowanie).
Pełna re-render, który zniszczy i ponownie zainicjować składnik (nazywając wszystkie haki cyklu życia i odbudowy widok) mogą być wykonane przy użyciu ng-template
, ng-container
a ViewContainerRef
w następujący sposób:
<div>
<ng-container #outlet >
</ng-container>
</div>
<ng-template #content>
<child></child>
</ng-template>
Następnie w komponencie mającym odniesienie do obu #outlet
i #content
możemy wyczyścić zawartość outletów i wstawić kolejną instancję komponentu potomnego:
@ViewChild("outlet", {read: ViewContainerRef}) outletRef: ViewContainerRef;
@ViewChild("content", {read: TemplateRef}) contentRef: TemplateRef<any>;
private rerender() {
this.outletRef.clear();
this.outletRef.createEmbeddedView(this.contentRef);
}
Dodatkowo początkową treść należy wstawić na AfterContentInit
hook:
ngAfterContentInit() {
this.outletRef.createEmbeddedView(this.contentRef);
}
Pełne działające rozwiązanie można znaleźć tutaj https://stackblitz.com/edit/angular-component-render .
ChangeDetectorRef.detectChanges()
jest zwykle najbardziej skoncentrowanym sposobem na zrobienie tego. ApplicationRef.tick()
jest zwykle zbyt dużym podejściem do młota kowalskiego.
Aby go użyć ChangeDetectorRef.detectChanges()
, potrzebujesz tego u góry swojego komponentu:
import { ChangeDetectorRef } from '@angular/core';
... wtedy zwykle nazywasz to aliasem, kiedy wstrzykujesz to w konstruktorze w ten sposób:
constructor( private cdr: ChangeDetectorRef ) { ... }
Następnie w odpowiednim miejscu nazywasz to tak:
this.cdr.detectChanges();
To, gdzie dzwonisz, ChangeDetectorRef.detectChanges()
może mieć duże znaczenie. Musisz w pełni zrozumieć cykl życia i dokładnie jak działa Twoja aplikacja i renderuje jej komponenty. Nic nie zastąpi tutaj całkowitego odrabiania pracy domowej i upewnienia się, że rozumiesz cykl życia Angular na wylot. Następnie, gdy już to zrozumiesz, możesz używać go ChangeDetectorRef.detectChanges()
odpowiednio (czasami bardzo łatwo jest zrozumieć, gdzie należy go użyć, innym razem może to być bardzo złożone).