Как принудительно перепрофилировать компонент в Angular 2?

Как заставить рендеринг компонента в Angular 2? В целях отладки при работе с Redux я хотел бы заставить компонент перерисовать его, это возможно?

Ответ 1

Рендеринг происходит после обнаружения изменений. Для принудительного обнаружения изменений, чтобы значения свойств компонентов, которые изменились, были переданы в DOM (а затем браузер отобразит эти изменения в представлении), вот несколько вариантов:

  • ApplicationRef.tick() - аналогично Angular 1 $rootScope.$digest() - т $rootScope.$digest() Проверить полное дерево компонентов
  • NgZone.run(callback) - аналогично $rootScope.$apply(callback) - т $rootScope.$apply(callback) Оценивает функцию обратного вызова внутри зоны Angular 2. Я думаю, но я не уверен, что это заканчивается проверкой полного дерева компонентов после выполнения функции обратного вызова.
  • ChangeDetectorRef.detectChanges() - аналогично $scope.$digest() - т.е. проверять только этот компонент и его дочерние элементы

Вам нужно будет импортировать, а затем внедрить ApplicationRef, NgZone или ChangeDetectorRef в ваш компонент.

Для вашего конкретного сценария я бы порекомендовал последний вариант, если изменился только один компонент.

Ответ 2

tx, нашел обходной путь, в котором я нуждался:

  constructor(private zone:NgZone) {
    // enable to for time travel
    this.appStore.subscribe((state) => {
        this.zone.run(() => {
            console.log('enabled time travel');
        });
    });

run zone.run заставит компонент повторно выполнить рендеринг

Ответ 3

Подход 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();
    }

}

Ответ 4

Другие ответы здесь предоставляют решения для запуска циклов обнаружения изменений, которые обновят представление компонента (что не совпадает с полным повторным рендерингом).

Полный повторный рендеринг, который приведет к уничтожению и повторной инициализации компонента (вызов всех хуков жизненного цикла и перестроение представления), можно выполнить с помощью ng-template, ng-container и ViewContainerRef следующим образом:

<div>
  <ng-container #outlet >
  </ng-container>
</div>

<ng-template #content>
  <child></child>
</ng-template>

Затем в компоненте, имеющем ссылку как на #outlet, так и на #content, мы можем очистить содержимое торговых точек и вставить другой экземпляр дочернего компонента:

@ViewChild("outlet", {read: ViewContainerRef}) outletRef: ViewContainerRef;
@ViewChild("content", {read: TemplateRef}) contentRef: TemplateRef<any>;

private rerender() {
    this.outletRef.clear();
    this.outletRef.createEmbeddedView(this.contentRef);
}

Дополнительно исходный контент должен быть вставлен в ловушку AfterContentInit:

ngAfterContentInit() {
    this.outletRef.createEmbeddedView(this.contentRef);
}

Полное рабочее решение можно найти здесь https://stackblitz.com/edit/angular-component-rerender.

Ответ 5

Я принудительно перезагружаю свой компонент, используя * ngIf.

Все компоненты внутри моего контейнера возвращаются к крюкам полного жизненного цикла.

В шаблоне:

<ng-container *ngIf="_reload">
    components here 
</ng-container>

Тогда в файле ts:

public _reload = true;

private reload() {
    setTimeout(() => this._reload = false);
    setTimeout(() => this._reload = true);
}

Ответ 6

ChangeDetectorRef.detectChanges() обычно является наиболее сфокусированным способом сделать это. ApplicationRef.tick() обычно слишком сложный подход кувалдой.

Чтобы использовать ChangeDetectorRef.detectChanges(), вам понадобится это вверху вашего компонента:

import {  ChangeDetectorRef } from '@angular/core';

... тогда обычно вы называете это псевдонимом, когда вставляете его в свой конструктор следующим образом:

constructor( private cdr: ChangeDetectorRef ) { ... }

Затем в соответствующем месте вы называете это так:

this.cdr.detectChanges();

Место, куда вы звоните ChangeDetectorRef.detectChanges(), может быть очень важным. Вам необходимо полностью понять жизненный цикл и то, как именно ваше приложение функционирует и отображает его компоненты. Здесь нет альтернативы тому, чтобы полностью выполнить домашнюю работу и убедиться, что вы понимаете жизненный цикл Angular наизнанку. Затем, как только вы поймете это, вы сможете использовать ChangeDetectorRef.detectChanges() надлежащим образом (иногда очень легко понять, где вы должны его использовать, в других случаях он может быть очень сложным).