Bagaimana cara memaksa rendering ulang komponen dalam Angular 2?

181

Bagaimana cara memaksa rendering ulang komponen dalam Angular 2? Untuk keperluan debug bekerja dengan Redux saya ingin memaksa komponen untuk merender ulang tampilan itu, apakah itu mungkin?

born2net
sumber
Apa yang Anda maksud dengan "rendering ulang". Perbarui ikatannya?
Günter Zöchbauer
Hanya pertanyaan singkat mengapa Anda harus memaksa rendering ulang?
Tuong Le
5
Kemungkinan duplikasi deteksi perubahan Triggering Angular2 secara manual
blo0p3r

Jawaban:

217

Rendering terjadi setelah deteksi perubahan. Untuk memaksa deteksi perubahan, sehingga nilai properti komponen yang telah berubah disebarkan ke DOM (dan kemudian browser akan membuat perubahan itu dalam tampilan), berikut adalah beberapa opsi:

  • ApplicationRef.tick () - mirip dengan Angular 1 $rootScope.$digest()- yaitu, periksa pohon komponen lengkap
  • NgZone.run (callback) - mirip dengan $rootScope.$apply(callback)- yaitu, mengevaluasi fungsi callback di dalam zona Angular 2. Saya pikir, tapi saya tidak yakin, bahwa ini akhirnya memeriksa struktur komponen lengkap setelah menjalankan fungsi callback.
  • ChangeDetectorRef.detectChanges () - mirip dengan $scope.$digest()- yaitu, periksa hanya komponen ini dan anak-anaknya

Anda akan perlu mengimpor dan kemudian menyuntikkan ApplicationRef, NgZoneatau ChangeDetectorRefke dalam komponen Anda.

Untuk skenario khusus Anda, saya akan merekomendasikan opsi terakhir jika hanya satu komponen yang berubah.

Mark Rajcok
sumber
1
Adakah kode yang berfungsi pada ChangeDetectorRef untuk versi final angular2? Saya sekarang menghadapi situasi di mana tampilan tidak diperbarui setelah permintaan posting http untuk membuat pengguna baru dan kemudian berhasil mendorong objek baru ke daftar pengguna lama yang ada (digunakan untuk beralih dalam tampilan). Cukup aneh this is the first time I am facing an update not working in ng2. Strategi deteksi perubahan adalah default, jadi saya tahu saya belum mengacaukan strategi deteksi perubahan.
Gary
1
@Gary, Anda harus memposting pertanyaan baru dan memasukkan komponen Anda dan kode layanan Anda (idealnya, termasuk penyedot minimal yang menunjukkan masalah ini). Masalah umum yang saya lihat adalah tidak menggunakan thiskonteks yang tepat dalam panggilan balik POST.
Mark Rajcok
Apakah Anda tahu jika saya dapat memicu pipa secara manual setiap kali saya melakukan perubahan? Saya sudah mencoba memicu deteksi perubahan tetapi pipa tidak memperbarui ... Saya juga mencoba dengan pure:falsedi dalam pipa. Ini berfungsi tetapi terlalu mahal (tidak efisien) untuk kasus penggunaan saya.
ncohen
1
@ncohen, saya tidak mengetahui cara apa pun untuk memicu pembaruan pipa secara manual. Anda bisa menggunakan pipa murni dan mengubah referensi objek kapan pun Anda ingin memicu pembaruan. Ini dibahas di bawah bagian "Pipa Murni" dari dokumen Pipa . Tergantung pada kasus penggunaan Anda, Anda mungkin ingin menggunakan properti komponen bukan pipa. Teknik ini dibahas secara singkat di akhir dokumen Pipes.
Mark Rajcok
1
@ T-makan, semua tautan sudah diperbaiki.
Mark Rajcok
47

tx, temukan solusi yang saya butuhkan:

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

running zone.run akan memaksa komponen untuk merender ulang

born2net
sumber
6
apa appStore dalam konteks ini - jenis variabel apa dan jenisnya? tampaknya dapat diamati ... tetapi yang dapat diamati berada di dalam komponen yang ingin saya segarkan dengan mengklik tombol ... dan saya tidak tahu cara mengakses metode / variabel komponen anak dari orang tua / lokasi saat ini
Abdeali Chandanwala
28

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

}
Feng Zhang
sumber
14

Saya paksa memuat ulang komponen saya menggunakan * ngIf.

Semua komponen di dalam wadah saya kembali ke kait siklus hidup penuh.

Dalam templat:

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

Kemudian di file ts:

public _reload = true;

private reload() {
    setTimeout(() => this._reload = false);
    setTimeout(() => this._reload = true);
}
orang gila
sumber
Terima kasih untuk ini, @loonis! Saya merasa ini harus bekerja, dan saya memiliki segalanya kecuali untuksetTimeout() . Sekarang milikku bekerja dengan solusi yang sederhana dan ringan!
LHM
jika aku bisa
menaikkan 10000+
1 hal yang perlu diperhatikan - wadah menghilang dan muncul lagi dapat menyebabkan perubahan ukuran dan halaman dapat berkedip
ghosh
9

Jawaban lain di sini memberikan solusi untuk memicu siklus deteksi perubahan yang akan memperbarui tampilan komponen (yang tidak sama dengan render penuh).

Re-render penuh, yang akan menghancurkan dan menginisialisasi ulang komponen (memanggil semua kait siklus hidup dan tampilan pembangunan kembali) dapat dilakukan dengan menggunakan ng-template, ng-containerdan ViewContainerRefdengan cara berikut:

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

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

Kemudian dalam komponen memiliki referensi ke keduanya #outletdan #contentkami dapat menghapus konten outlet dan memasukkan instance komponen anak yang lain:

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

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

Selain itu, konten awal harus dimasukkan pada AfterContentInithook:

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

Solusi kerja lengkap dapat ditemukan di sini https://stackblitz.com/edit/angular-component-rerender .

Pavel Gurecki
sumber
1

ChangeDetectorRef.detectChanges() biasanya cara paling fokus untuk melakukan ini. ApplicationRef.tick()biasanya terlalu banyak pendekatan palu godam.

Untuk menggunakannya ChangeDetectorRef.detectChanges(), Anda memerlukan ini di bagian atas komponen Anda:

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

... lalu, biasanya Anda menyebutkan itu ketika Anda menyuntikkannya dalam konstruktor Anda seperti ini:

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

Kemudian, di tempat yang tepat , Anda menyebutnya seperti ini:

this.cdr.detectChanges();

Tempat Anda menelepon ChangeDetectorRef.detectChanges()bisa sangat signifikan. Anda harus benar - benar memahami siklus hidup dan bagaimana aplikasi Anda berfungsi dan menampilkan komponen-komponennya. Tidak ada pengganti di sini untuk benar-benar melakukan pekerjaan rumah Anda dan memastikan Anda memahami siklus hidup sudut luar. Kemudian, setelah Anda memahami itu, Anda dapat menggunakannya dengan ChangeDetectorRef.detectChanges()tepat (kadang-kadang sangat mudah untuk memahami di mana Anda harus menggunakannya, di lain waktu itu bisa sangat kompleks).

Chris Halcrow
sumber