Angular 2でコンポーネントの再レンダリングを強制する方法は?


181

Angular 2でコンポーネントの再レンダリングを強制する方法は?Reduxでのデバッグ目的で、コンポーネントにビューの再レンダリングを強制したいのですが、それは可能ですか?


「再レンダリング」とはどういう意味ですか。バインディングを更新しますか?
ギュンターZöchbauer

なぜあなたは再レンダリングを強制する必要があるのですか?
Tuong Le

回答:


217

レンダリングは変更の検出後に行われます。変更の検出を強制し、変更されたコンポーネントのプロパティ値がDOMに伝達されるように(そして、ブラウザーがそれらの変更をビューに表示するように)、いくつかのオプションを次に示します。

  • ApplicationRef.tick() -Angular 1に似ています$rootScope.$digest()-つまり、コンポーネントツリー全体をチェックします
  • NgZone.run(callback) -に似ています$rootScope.$apply(callback) -つまり、Angular 2ゾーン内のコールバック関数を評価します。コールバック関数を実行した後、コンポーネントツリー全体をチェックすることになると思いますが、よくわかりません。
  • ChangeDetectorRef.detectChanges() -に似ています$scope.$digest()-つまり、このコンポーネントとその子のみをチェックします

あなたは、インポートして注入する必要がありますApplicationRefNgZoneまたはChangeDetectorRefあなたのコンポーネントに。

特定のシナリオでは、単一のコンポーネントのみが変更されている場合は、最後のオプションをお勧めします。


1
angular2の最終バージョンのChangeDetectorRefで動作するコードはありますか?新しいユーザーを作成するためのhttpのpostリクエストの後でビューが更新されず、成功したときに新しいオブジェクトを既存の古いユーザーリスト(ビューの反復に使用)にプッシュする状況に直面しています。かなり奇妙なことthis is the first time I am facing an update not working in ng2です。変更検出戦略はデフォルトなので、変更検出戦略に失敗していません。
Gary

1
@Gary、新しい質問を投稿し、コンポーネントとサービスコードを含める必要があります(理想的には、問題を示す最小限のプランカーを含めます)。私が目にした一般的な問題thisは、POSTコールバックで適切なコンテキストを使用していないことです。
Mark Rajcok 2016年

変更を実行するたびにパイプを手動でトリガーできるかどうか知っていますか?変更検出をトリガーしようとしましたが、パイプが更新されません...パイプでも試してみpure:falseました。それは機能しますが、私のユースケースには高すぎます(非効率的)。
ncohen 2017年

1
@ncohen、パイプの更新を手動でトリガーする方法は知りません。純粋なパイプを使用して、更新をトリガーするたびにオブジェクト参照を変更できます。これについては、Pipesドキュメントの「Pure Pipes」セクションで説明しています。ユースケースによっては、パイプの代わりにコンポーネントプロパティを使用したい場合があります。このテクニックについては、Pipesドキュメントの最後で簡単に説明しています。
マークライコック2017年

1
@ N-ate、すべてのリンクが修正されています。
マークライコック2018

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-templateng-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()非常に重要です。ライフサイクルを完全に理解し、アプリケーションが機能してコンポーネントをレンダリングする方法を正確に理解する必要があります。ここで宿題を完全に行い、Angularライフサイクルを完全に理解することの代わりはありません。次に、それを理解したら、ChangeDetectorRef.detectChanges()適切に使用できます(使用する場所を理解するのが非常に簡単な場合もあれば、非常に複雑な場合もあります)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.