Як змусити повторне відображення компонента в куті 2?


181

Як змусити повторне відображення компонента в куті 2? Для цілей налагодження роботи з Redux я хотів би змусити компонент повторно переглянути його перегляд, чи це можливо?


Що ви маєте на увазі під «повторним рендерінгом». Оновити прив’язки?
Günter Zöchbauer

Лише швидке запитання, чому потрібно змусити повторне надання?
Tuong Le

Відповіді:


217

Відображення відбувається після виявлення змін. Щоб примусити виявлення змін, щоб значення властивостей компонентів поширилися на DOM (і тоді браузер видасть ці зміни у представленні), ось кілька варіантів:

  • ApplicationRef.tick () - схожий на Angular 1's $rootScope.$digest()- тобто перевірити повне дерево компонентів
  • NgZone.run (зворотний виклик) - подібний $rootScope.$apply(callback)- тобто, оцініть функцію зворотного дзвінка всередині зони Angular 2. Я думаю, але я не впевнений, що це закінчує перевірку повного дерева компонентів після виконання функції зворотного виклику.
  • ChangeDetectorRef.detectChanges () - подібний до $scope.$digest()- тобто перевіряйте лише цей компонент та його діти

Вам потрібно буде імпортувати , а потім ін'єкційні ApplicationRef, NgZoneабо ChangeDetectorRefв компонент.

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


1
Будь-який робочий код на ChangeDetectorRef для остаточної версії angular2? Зараз я зіткнувся з ситуацією, коли представлення даних не оновлюється після запиту повідомлення від http про створення нового користувача, а потім з успіхом виштовхує новий об'єкт до існуючого старого списку користувачів (використовується для перегляду в ітерації). Досить дивно, що this is the first time I am facing an update not working in ng2. Стратегія виявлення змін за замовчуванням, тому я знаю, що я не переплутався зі стратегією виявлення змін.
Гері

1
@Gary, ви повинні опублікувати нове запитання та включити свій компонент та код послуги (в ідеалі - мінімум викрадачів, що демонструють проблему). Поширена проблема, яку я бачив, - це не використання належного thisконтексту у зворотному режимі виклику POST.
Марк Райкок

Чи знаєте ви, чи можу я вручну запускати труби кожного разу, коли виконую заміну? Я намагався ініціювати виявлення змін, але труба не оновлюється ... Я також намагався pure:falseв роботі. Це працює, але це занадто дорого (неефективно) для мого використання.
ncohen

1
@ncohen, я не знаю жодного способу вручну запустити оновлення труби. Ви можете використовувати чисту трубу та змінювати посилання на об'єкт кожного разу, коли хочете запустити оновлення. Про це йдеться в розділі "Чисті труби" в документі Труби . Залежно від випадку використання, ви можете використовувати властивість компонента замість труби. Цей прийом коротко обговорюється в кінці докт. Труб.
Марк Райкок

1
@ N-ate, всі посилання виправлені.
Марк Райкок

47

tx, знайшов потрібне вирішення:

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

Запущений zone.run змусить компонент повторно візуалізувати


6
що таке appStore в цьому контексті - яка змінна та її тип? начебто спостерігається ... але моє спостереження знаходиться всередині компонента, який я хочу оновити одним натисканням кнопки ... і я не знаю, як отримати доступ до методу / змінної дочірнього компонента з батьківського / поточного місця розташування
Abdeali Chandanwala

28

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

}

14

Я змушую перезавантажувати свій компонент за допомогою * ngIf.

Всі компоненти всередині мого контейнера повертаються до повних гачків життєвого циклу.

У шаблоні:

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

Потім у файлі ts:

public _reload = true;

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

Дякую за це, @loonis! Я відчував, що це має працювати, і у мене було все, крім самого setTimeout(). Зараз моя працює з простим і легким рішенням!
LHM

якби я міг підтвердити це 10000+ разів ..
Yazan Khalaileh

1 зауважимо - контейнер зникає і з’являється знову може спричинити зміни розміру, і сторінка може мерехтіти
ghosh

9

Інші відповіді тут пропонують рішення для запуску циклів виявлення змін, які оновлюють вигляд компонента (що не є таким, як повне рендеринга).

Повний повторне рендер, який знищить і переініціалізіровать компонент (виклик все гаки життєвий цикл і відновлення зору) може бути зроблено за допомогою 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 .


1

ChangeDetectorRef.detectChanges()зазвичай це найбільш цілеспрямований спосіб зробити це. ApplicationRef.tick()зазвичай занадто багато підходу кувалди.

Для використання ChangeDetectorRef.detectChanges()вам знадобиться це у верхній частині вашого компонента:

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

... тоді зазвичай ви псевдонім, коли ви вводите його у свій конструктор так:

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

Потім у відповідному місці ви називаєте це так:

this.cdr.detectChanges();

Те, де ви телефонуєте, ChangeDetectorRef.detectChanges()може бути дуже важливим. Вам потрібно повністю зрозуміти життєвий цикл і те, як саме функціонує ваша програма та відображає її компоненти. Тут немає замінника, щоб повністю виконати домашнє завдання та переконатися, що ви розумієте кутовий життєвий цикл зсередини. Потім, як тільки ви зрозумієте це, ви можете використовувати ChangeDetectorRef.detectChanges()відповідним чином (іноді дуже просто зрозуміти, де слід його використовувати, в іншому випадку це може бути дуже складно).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.