Komponen saya memiliki gaya yang bergantung pada datetime saat ini. Dalam komponen saya, saya punya fungsi berikut.
private fontColor( dto : Dto ) : string {
// date d'exécution du dto
let dtoDate : Date = new Date( dto.LastExecution );
(...)
let color = "hsl( " + hue + ", 80%, " + (maxLigness - lightnessAmp) + "%)";
return color;
}
lightnessAmp
dihitung dari datetime saat ini. Warnanya berubah jika dtoDate
dalam 24 jam terakhir.
Kesalahan yang tepat adalah sebagai berikut:
Ekspresi telah berubah setelah diperiksa. Nilai sebelumnya: 'hsl (123, 80%, 49%)'. Nilai sekarang: 'hsl (123, 80%, 48%)'
Saya tahu pengecualian muncul dalam mode pengembangan hanya saat nilai diperiksa. Jika nilai yang dicentang berbeda dari nilai yang diperbarui, pengecualian dilemparkan.
Jadi saya mencoba memperbarui datetime saat ini di setiap siklus hidup dalam metode kait berikut untuk mencegah pengecualian:
ngAfterViewChecked()
{
console.log( "! changement de la date du composant !" );
this.dateNow = new Date();
}
... tetapi tanpa hasil.
angular
typescript
time
styles
components
Anthony Brenelière
sumber
sumber
Jawaban:
Jalankan deteksi perubahan secara eksplisit setelah perubahan:
sumber
ngOnInit()
biasanya tempat pertama. Jika kode tergantung pada DOM yang diberikanngAfterViewInit()
ataungAfterContentInit()
merupakan opsi berikutnya.ngOnChanges()
cocok jika kode harus dieksekusi setiap kali input diubah.ngDoCheck()
adalah untuk deteksi perubahan kustom. Sebenarnya saya tidak tahungAfterViewChecked()
digunakan untuk apa. Saya pikir itu disebut sebelum atau sesudahngAfterViewInit()
.clientWidth
, dll.TL; DR
Meskipun ini merupakan solusi, kadang-kadang sangat sulit untuk menyelesaikan masalah ini dengan cara yang lebih baik, jadi jangan salahkan diri Anda jika Anda menggunakan pendekatan ini. Tidak apa-apa.
Contoh : Masalah awal [ tautan ], Diselesaikan dengan
setTimeout()
[ tautan ]Bagaimana cara menghindarinya
Secara umum kesalahan ini biasanya terjadi setelah Anda menambahkan suatu tempat (bahkan dalam komponen induk / anak)
ngAfterViewInit
. Jadi pertanyaan pertama adalah bertanya pada diri sendiri - dapatkah saya hidup tanpanyangAfterViewInit
? Mungkin Anda memindahkan kode di suatu tempat (ngAfterViewChecked
mungkin menjadi alternatif).Contoh : [ tautan ]
Juga
Juga hal-hal async
ngAfterViewInit
yang mempengaruhi DOM dapat menyebabkan ini. Juga dapat diselesaikan melaluisetTimeout
atau dengan menambahkandelay(0)
operator di dalam pipa:Contoh : [ tautan ]
Bacaan yang bagus
Artikel bagus tentang cara men-debug ini dan mengapa itu terjadi: tautan
sumber
Seperti yang disebutkan oleh @leocaseiro tentang masalah github .
sumber
Dia Anda pergi dua solusi!
1. Ubah ChangeDetectionStrategy ke OnPush
Untuk solusi ini, Anda pada dasarnya memberi tahu sudut:
Perbaikan cepat:
Ubah komponen Anda sehingga akan digunakan
ChangeDetectionStrategy.OnPush
Dengan ini, semuanya sepertinya tidak berfungsi lagi. Itu karena mulai sekarang Anda harus membuat panggilan Angular
detectChanges()
secara manual.Berikut ini tautan yang membantu saya memahami ChangeDetectionStrategy benar: https://alligator.io/angular/change-detection-strategy/
2. Memahami Ekspresi yang DiubahSetelahMemilikiBeenTidak Teror
Berikut ini adalah ekstrak kecil dari jawaban tomonari_t tentang penyebab kesalahan ini, saya hanya mencoba memasukkan bagian-bagian yang membantu saya untuk memahami hal ini.
Artikel lengkap menunjukkan contoh kode nyata tentang setiap titik yang ditampilkan di sini.
Penyebab dasarnya adalah siklus hidup sudut:
Operasi berikut sedang diperiksa pada siklus digest:
Jadi, kesalahan dilemparkan ketika nilai yang dibandingkan berbeda. , blogger Max Koretskyi menyatakan:
Dan akhirnya, inilah beberapa contoh dunia nyata yang biasanya menyebabkan kesalahan ini:
Setiap sampel dapat ditemukan di sini (plunkr), dalam kasus saya masalahnya adalah instantiasi komponen dinamis.
Juga, berdasarkan pengalaman saya sendiri, saya sangat menyarankan semua orang untuk menghindari
setTimeout
solusi, dalam kasus saya menyebabkan loop "hampir" tak terbatas (21 panggilan yang saya tidak mau tunjukkan kepada Anda bagaimana memprovokasi mereka),Saya akan merekomendasikan untuk selalu mengingat siklus hidup Angular sehingga Anda dapat memperhitungkan bagaimana mereka akan terpengaruh setiap kali Anda mengubah nilai komponen lain. Dengan kesalahan ini, Angular memberi tahu Anda:
Blog yang sama juga mengatakan:
Panduan singkat bagi saya adalah untuk mempertimbangkan setidaknya dua hal berikut ini saat coding ( saya akan mencoba melengkapinya dari waktu ke waktu ):
@Input
dan@Output
arahan, cobalah untuk menghindari memicu perubahan siklus lyf kecuali komponen sepenuhnya diinisialisasi.this.cdr.detectChanges();
karena dapat memicu lebih banyak kesalahan, khususnya ketika Anda berurusan dengan banyak data dinamisthis.cdr.detectChanges();
wajib, pastikan bahwa variabel (@Input, @Output, etc
) yang digunakan diisi / diinisialisasi pada kait deteksi kanan (OnInit, OnChanges, AfterView, etc
)Juga
Jika Anda ingin sepenuhnya memahami Angular Life Hook, saya sarankan Anda untuk membaca dokumentasi resmi di sini:
sumber
ChangeDetectionStrategy
untukOnPush
memperbaikinya bagi saya. Saya memiliki komponen sederhana, yang memiliki[disabled]="isLastPage()"
. Metode itu membacaMatPaginator
-ViewChild dan kembalithis.paginator !== undefined ? this.paginator.pageIndex === this.paginator.getNumberOfPages() - 1 : true;
. Paginator tidak tersedia segera, tapi setelah itu telah terikat dengan menggunakan@ViewChild
. MengubahChangeDetectionStrategy
kesalahan yang dihapus - dan fungsi masih ada seperti sebelumnya. Tidak yakin kekurangan yang saya miliki sekarang, tapi terima kasih!OnPush
adalah Anda harus menggunakanthis.cdr.detectChanges()
setiap kali Anda ingin komponen Anda untuk menyegarkan. Saya kira Anda sudah menggunakannyaDalam kasus kami, kami TETAP dengan menambahkan changeDetection ke dalam komponen dan memanggil detectChanges () di ngAfterContentChecked, kode sebagai berikut
sumber
Saya pikir solusi terbaik dan terbersih yang dapat Anda bayangkan adalah ini:
Diuji dengan Angular 5.2.9
sumber
Pekerjaan kecil di sekitar saya digunakan berkali-kali
Saya terutama mengganti "null" dengan beberapa variabel yang saya gunakan di controller.
sumber
Meskipun sudah ada banyak jawaban dan tautan ke artikel yang sangat bagus tentang deteksi perubahan, saya ingin memberikan dua sen saya di sini. Saya pikir cek ada karena suatu alasan jadi saya berpikir tentang arsitektur aplikasi saya dan menyadari bahwa perubahan dalam tampilan dapat ditangani dengan menggunakan
BehaviourSubject
dan kait siklus hidup yang benar. Jadi inilah yang saya lakukan untuk solusi.Jadi saya akhirnya mendapatkan kelas JavaScript yang mendasarinya, dan perlu menginisialisasi header kalender saya sendiri untuk komponen. Itu mengharuskan
ViewChild
untuk dirender sebelum orang tua saya diberikan, yang bukan cara Angular bekerja. Inilah mengapa saya membungkus nilai yang saya butuhkan untuk template saya diBehaviourSubject<View>(null)
:Selanjutnya, ketika saya bisa memastikan tampilan dicentang, saya memperbarui subjek itu dengan nilai dari
@ViewChild
:Kemudian, dalam templat saya, saya hanya menggunakan
async
pipa. Tidak ada peretasan dengan deteksi perubahan, tidak ada kesalahan, bekerja dengan lancar.Harap jangan ragu untuk bertanya apakah Anda membutuhkan detail lebih lanjut.
sumber
Gunakan nilai formulir default untuk menghindari kesalahan.
Alih-alih menggunakan jawaban yang diterima dari menerapkan detectChanges () di ngAfterViewInit () (yang juga memecahkan kesalahan dalam kasus saya), saya malah memutuskan untuk menyimpan nilai default untuk bidang formulir yang diperlukan secara dinamis, sehingga ketika formulir tersebut kemudian diperbarui, validitasnya tidak berubah jika pengguna memutuskan untuk mengubah opsi pada formulir yang akan memicu bidang yang diperlukan baru (dan menyebabkan tombol kirim dinonaktifkan).
Ini menyimpan sedikit kode dalam komponen saya, dan dalam kasus saya kesalahannya dihindari sama sekali.
sumber
this.cdr.detectChanges()
Saya mendapatkan kesalahan itu karena saya mendeklarasikan variabel dan kemudian ingin
mengubah nilainya menggunakan
ngAfterViewInit
untuk memperbaikinya saya beralih dari
untuk
sumber