How to force a component's re-rendering in Angular 2? For debug purposes working with Redux i'd like to force a component to re-render it's view, is that possible?
-
What do you mean by "re-rendering". Update the bindings?Günter Zöchbauer– Günter Zöchbauer2016-01-30 18:23:44 +00:00Commented Jan 30, 2016 at 18:23
-
Just a quick question why you need to force re-rendering?Tuong Le– Tuong Le2016-10-18 03:16:07 +00:00Commented Oct 18, 2016 at 3:16
-
5Possible duplicate of Triggering Angular2 change detection manuallyblo0p3r– blo0p3r2016-11-09 15:46:25 +00:00Commented Nov 9, 2016 at 15:46
6 Answers
Rendering happens after change detection. To force change detection, so that component property values that have changed get propagated to the DOM (and then the browser will render those changes in the view), here are some options:
- ApplicationRef.tick() - similar to Angular 1's
$rootScope.$digest()-- i.e., check the full component tree - NgZone.run(callback) - similar to
$rootScope.$apply(callback)-- i.e., evaluate the callback function inside the Angular 2 zone. I think, but I'm not sure, that this ends up checking the full component tree after executing the callback function. - ChangeDetectorRef.detectChanges() - similar to
$scope.$digest()-- i.e., check only this component and its children
You will need to import and then inject ApplicationRef, NgZone, or ChangeDetectorRef into your component.
For your particular scenario, I would recommend the last option if only a single component has changed.
6 Comments
this is the first time I am facing an update not working in ng2. The change detection strategy is default so i know i have not messed up with the change detection strategy.this context in the POST callback.ChangeDetectorRef approach
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();
}
}
Comments
tx, found the workaround I needed:
constructor(private zone:NgZone) {
// enable to for time travel
this.appStore.subscribe((state) => {
this.zone.run(() => {
console.log('enabled time travel');
});
});
running zone.run will force the component to re-render
1 Comment
I force reload my component using *ngIf.
All the components inside my container goes back to the full lifecycle hooks .
In the template :
<ng-container *ngIf="_reload">
components here
</ng-container>
Then in the ts file :
public _reload = true;
private reload() {
setTimeout(() => this._reload = false);
setTimeout(() => this._reload = true);
}
5 Comments
setTimeout(). Now mine is working with a simple and lightweight solution!Other answers here provide solutions for triggering change detection cycles that will update component's view (which is not same as full re-render).
Full re-render, which would destroy and reinitialize component (calling all lifecycle hooks and rebuilding view) can be done by using ng-template, ng-container and ViewContainerRef in following way:
<div>
<ng-container #outlet >
</ng-container>
</div>
<ng-template #content>
<child></child>
</ng-template>
Then in component having reference to both #outlet and #content we can clear outlets' content and insert another instance of child component:
@ViewChild("outlet", {read: ViewContainerRef}) outletRef: ViewContainerRef;
@ViewChild("content", {read: TemplateRef}) contentRef: TemplateRef<any>;
private rerender() {
this.outletRef.clear();
this.outletRef.createEmbeddedView(this.contentRef);
}
Additionally initial content should be inserted on AfterContentInit hook:
ngAfterContentInit() {
this.outletRef.createEmbeddedView(this.contentRef);
}
Full working solution can be found here https://stackblitz.com/edit/angular-component-rerender .
1 Comment
ngAfterViewInit. BTW, it interestingly is the only solution that worked for me when input's held the previous values despite form model was correct. This occurred when I was switching between routes differentiated by the :id route. In the end I had to call the rerender function every time that navigation ended.ChangeDetectorRef.detectChanges() is usually the most focused way of doing this. ApplicationRef.tick() is usually too much of a sledgehammer approach.
To use ChangeDetectorRef.detectChanges(), you'll need this at the top of your component:
import { ChangeDetectorRef } from '@angular/core';
... then, usually you alias that when you inject it in your constructor like this:
constructor( private cdr: ChangeDetectorRef ) { ... }
Then, in the appropriate place, you call it like this:
this.cdr.detectChanges();
Where you call ChangeDetectorRef.detectChanges() can be highly significant. You need to completely understand the life cycle and exactly how your application is functioning and rendering its components. There's no substitute here for completely doing your homework and making sure you understand the Angular lifecycle inside out. Then, once you understand that, you can use ChangeDetectorRef.detectChanges() appropriately (sometimes it's very easy to understand where you should use it, other times it can be very complex).