Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to force a component's re-rendering in Angular 2?

People also ask

How do you're render template in angular?

The very basic approach works by wrapping the element you want to rerender inside a ng-template element that gets rendered into a ng-container . On rerender you can just clear the content of the ng-container and create a new component from the ng-element .


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.


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


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();
    }

}

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);
}

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 .


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).