Memicu deteksi perubahan secara manual di Angular

387

Saya sedang menulis komponen Angular yang memiliki properti Mode(): string.

Saya ingin dapat menyetel properti ini secara terprogram tidak menanggapi peristiwa apa pun.

Masalahnya adalah bahwa dengan tidak adanya acara browser, pengikatan templat {{Mode}}tidak diperbarui.

Apakah ada cara untuk memicu deteksi perubahan ini secara manual?

jz87
sumber

Jawaban:

640

Coba salah satu dari ini:

  • ApplicationRef.tick()- Mirip dengan AngularJS $rootScope.$digest()- yaitu, periksa pohon komponen lengkap
  • NgZone.run(callback)- mirip dengan $rootScope.$apply(callback)- yaitu, mengevaluasi fungsi panggilan balik di dalam zona Angular. 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 dapat menyuntikkan ApplicationRef, NgZoneatau ChangeDetectorRefke dalam komponen Anda.

Mark Rajcok
sumber
1
Terima kasih, saya memilih solusi ke-3 agar tidak memeriksa semuanya, karena perubahannya cukup terlokalisasi. Saya harus menyelidiki opsi lain ketika saya punya lebih banyak waktu. Apakah ada implikasi kinerja dengan setiap pilihan?
jz87
36
+1 untuk ChangeDetectorRef.detectChanges(). validator diaktifkan sebelum arahan saya dapat memperbarui nilai input.
ps2goat
7
ApplicationRef.tick () dan ChangeDetectorRef.detectChanges () masih ada di final 2.0.0.
Max Mumford
51
Hanya berpikir saya akan menyebutkan ini. Ini bukan metode statis, mereka adalah metode instan. Anda harus menyuntikkan kelas-kelas ini sebagai layanan.
Stephen Paul
1
ApplicationRef.tick () membantu menyelesaikan masalah dengan FireFox v17 (<20)
Dan J
124

Saya menggunakan referensi jawaban yang diterima dan ingin memberi contoh, karena dokumentasi Angular 2 sangat sulit dibaca, saya harap ini lebih mudah:

  1. Impor NgZone:

    import { Component, NgZone } from '@angular/core';
    
  2. Tambahkan ke konstruktor kelas Anda

    constructor(public zone: NgZone, ...args){}
    
  3. Jalankan kode dengan zone.run:

    this.zone.run(() => this.donations = donations)
    
situs
sumber
6
di mana Anda harus meletakkan zone.runkode dan apa sebenarnya donations?
suku
1
@suku donasi adalah properti apa pun yang ingin Anda perbarui, jadi ini adalah this.foo = bar. zone.run pergi ke mana pun Anda ingin memperbarui barang.
Matius Opsional Meehan
4
Saya menggunakan solusi ini untuk memaksa pembaruan tampilan saat menggunakan document.addEventListener ("resume", callback)
marcovtwout
71

Saya dapat memperbaruinya dengan markForCheck ()

Impor ChangeDetectorRef

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

Suntikkan dan instantiate

constructor(private ref: ChangeDetectorRef) { 
}

Akhirnya tandai deteksi perubahan untuk dilakukan

this.ref.markForCheck();

Berikut ini contoh di mana markForCheck () berfungsi dan mendeteksiChanges () tidak.

https://plnkr.co/edit/RfJwHqEVJcMU9ku9XNE7?p=preview

EDIT: Contoh ini tidak menggambarkan masalah lagi :( Saya percaya itu mungkin menjalankan versi Angular yang lebih baru di mana itu diperbaiki.

(Tekan STOP / RUN untuk menjalankannya lagi)

Nuno Tomas
sumber
Goo point untuk detectChanges () tidak berfungsi. Saya telah memperhatikan masalah yang sama dan menemukan bahwa itu berfungsi jika deteksi perubahan ada OnPush. Akan baik untuk mendapatkan penjelasan untuk itu ...
Christian
2
Sepertinya detectChanges benar-benar berfungsi di plunker ini? Apakah saya melewatkan sesuatu?
Jared_C
1
Anda harus mencatat bahwa ChangeDetectorRef hanya berfungsi di Komponen
kevinius
(!) Ini adalah contoh yang buruk, saya minta maaf. Contoh tidak menunjukkan apa-apa. Item pertama baru saja ditimpa. Cukup sesuaikan timer sedikit ...
Peter Stegnar
Contoh ini tidak menggambarkan masalah lagi :( Saya percaya ini mungkin menjalankan versi Angular yang lebih baru di mana itu diperbaiki.
Nuno Tomas
7

Di Angular 2+, coba dekorator @Input

Hal ini memungkinkan untuk mengikat properti yang bagus antara komponen induk dan anak.

Pertama buat variabel global di induk untuk memegang objek / properti yang akan diteruskan ke anak.

Selanjutnya buat variabel global pada anak untuk memegang objek / properti yang diteruskan dari induknya.

Kemudian di html induk, tempat templat turunan digunakan, tambahkan notasi tanda kurung siku dengan nama variabel turunan, lalu setel sama dengan nama variabel induk. Contoh:

<child-component-template [childVariable] = parentVariable>
</child-component-template>

Akhirnya, di mana properti anak didefinisikan dalam komponen anak, tambahkan dekorator Input:

@Input()
public childVariable: any

Ketika variabel induk Anda diperbarui, itu harus melewati pembaruan ke komponen anak, yang akan memperbarui html-nya.

Juga, untuk memicu fungsi dalam komponen anak, lihat ngOnChanges.

Jeremy Swagger
sumber
2
TIDAK ... itulah masalahnya ... jika Anda memperbarui dalam induk ... katakanlah untuk exmaple diperbarui "dengan referensi" dalam metode statis anak tidak akan mengambilnya karena deteksi deteksi belum terjadi
Bhail
Saya punya masalah yang sama selama berhari-hari sekarang. Saya mencoba mengambil data dari PHP backend dan data tidak memperbarui sama sekali. Di Microsoft Edge berfungsi dengan baik tetapi pada browser lain tidak. Saya terus mendapatkan data yang pertama kali saya mulai tetapi jika data berubah tidak dapat diperbarui pada tampilan
el6976
1

ChangeDetectorRef.detectChanges () - mirip dengan $ scope. $ Digest () - yaitu, periksa hanya komponen ini dan anak-anaknya

Chetann
sumber