Tolong jelaskan kepada saya mengapa saya terus mendapatkan kesalahan ini: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked.
Jelas, saya hanya mendapatkannya dalam mode dev, itu tidak terjadi pada build produksi saya, tapi itu sangat menjengkelkan dan saya tidak mengerti manfaat memiliki kesalahan di lingkungan dev saya yang tidak akan muncul di prod - -mungkin karena kurangnya pemahaman saya.
Biasanya, perbaikannya cukup mudah, saya hanya membungkus kode yang menyebabkan kesalahan dalam setTimeout seperti ini:
setTimeout(()=> {
this.isLoading = true;
}, 0);
Atau paksa deteksi perubahan dengan konstruktor seperti ini constructor(private cd: ChangeDetectorRef) {}
::
this.isLoading = true;
this.cd.detectChanges();
Tetapi mengapa saya terus-menerus mengalami kesalahan ini? Saya ingin memahaminya sehingga saya dapat menghindari perbaikan yang tidak rapi ini di masa depan.
sumber
Jawaban:
Saya punya masalah serupa. Melihat dokumentasi siklus hidup kait , aku berubah
ngAfterViewInit
untukngAfterContentInit
dan bekerja.sumber
setTimeout
seperti yang Anda tunjukkan di atas berhasil. Terima kasih!ngAfterContentChecked
bekerja di sini sementarangAfterContentInit
masih melempar kesalahan.Kesalahan ini menunjukkan masalah nyata dalam aplikasi Anda, oleh karena itu masuk akal untuk melemparkan pengecualian.
Dalam
devMode
deteksi perubahan tambahkan giliran tambahan setelah setiap deteksi perubahan reguler dijalankan untuk memeriksa apakah model telah berubah.Jika model telah berubah antara perubahan deteksi perubahan reguler dan tambahan, ini menunjukkan bahwa baik
yang keduanya buruk, karena tidak jelas bagaimana melanjutkan karena modelnya mungkin tidak pernah stabil.
Jika Angular menjalankan deteksi perubahan hingga model stabil, mungkin akan berjalan selamanya. Jika Angular tidak menjalankan deteksi perubahan, maka tampilan mungkin tidak mencerminkan keadaan model saat ini.
Lihat juga Apa perbedaan antara mode produksi dan pengembangan di Angular2?
sumber
ngOnInit
ataungOnChanges
untuk memodifikasi model (beberapa panggilan balik siklus memungkinkan memodifikasi model yang lain tidak, saya tidak ingat sendiri persis mana yang melakukan atau tidak). Jangan mengikat metode atau fungsi dalam tampilan, melainkan mengikat ke bidang dan memperbarui bidang dalam penangan acara. Jika Anda harus mengikat ke metode, pastikan bahwa mereka selalu mengembalikan contoh nilai yang sama selama tidak ada perubahan. Deteksi perubahan akan memanggil metode ini banyak.changeRef.detectChanges()
adalah solusi / menekan kesalahan, adalah buktinya. Ini seperti memodifikasi keadaan di$scope.$watch()
dalam Angular 1.cdRef.detectChanges()
hanya diperlukan dalam beberapa kasus tepi yang aneh dan Anda harus melihat dengan hati-hati ketika Anda membutuhkannya sehingga Anda mengerti mengapa.Banyak pengertian muncul begitu saya memahami Angular Lifecycle Hooks dan hubungannya dengan deteksi perubahan.
Saya mencoba membuat Angular memperbarui bendera global yang terikat pada
*ngIf
elemen, dan saya mencoba mengubah bendera itu di dalamngOnInit()
kait siklus hidup komponen lain.Menurut dokumentasi, metode ini dipanggil setelah Angular mendeteksi perubahan:
Jadi memperbarui bendera di dalamnya
ngOnChanges()
tidak akan memulai deteksi perubahan. Kemudian, begitu deteksi perubahan dipicu secara alami lagi, nilai bendera telah berubah dan kesalahan dilemparkan.Dalam kasus saya, saya mengubah ini:
Untuk ini:
dan itu memperbaiki masalah :)
sumber
router.navigate
) saat memuat ke sebuah fragmen jika ada di URL. Kode ini awalnya ditempatkan diAfterViewInit
tempat saya menerima kesalahan, kemudian saya pindah seperti yang Anda katakan kepada konstruktor tetapi tidak menghormati fragmen. Pindah kengOnInit
diselesaikan :) terima kasih!setInterval()
karya juga jika perlu memecat kode acara seumur hidup lainnya.Memperbarui
Saya sangat merekomendasikan memulai dengan respons diri OP terlebih dahulu: pikirkan dengan benar tentang apa yang bisa dilakukan dalam
constructor
vs apa yang harus dilakukanngOnChanges()
.Asli
Ini lebih merupakan catatan samping daripada jawaban, tetapi mungkin membantu seseorang. Saya menemukan masalah ini ketika mencoba membuat keberadaan tombol tergantung pada kondisi formulir:
Sejauh yang saya tahu, sintaks ini mengarah ke tombol yang ditambahkan dan dihapus dari DOM berdasarkan kondisi. Yang pada gilirannya mengarah pada
ExpressionChangedAfterItHasBeenCheckedError
.Perbaikan dalam kasus saya (meskipun saya tidak mengklaim memahami implikasi penuh dari perbedaan), adalah
display: none
sebagai gantinya digunakan :sumber
[hidden]
bukan bagian yang sangat bertele-tele[style.display]
. :)[hidden]
tidak akan selalu memiliki perilaku yang sama sepertidisplay: none
Ada jawaban yang menarik tetapi saya sepertinya tidak menemukan satu yang cocok dengan kebutuhan saya, yang terdekat dari @ chittrang-mishra yang hanya merujuk pada satu fungsi tertentu dan tidak beberapa toggle seperti pada aplikasi saya.
Saya tidak ingin menggunakan
[hidden]
untuk mengambil keuntungan dari*ngIf
tidak menjadi bagian dari DOM, jadi saya menemukan solusi berikut yang mungkin bukan yang terbaik untuk semua karena menekan kesalahan daripada memperbaikinya, tetapi dalam kasus saya di mana saya tahu hasil akhirnya sudah benar, sepertinya ok untuk aplikasi saya.Apa yang saya lakukan adalah mengimplementasikan
AfterViewChecked
, menambahconstructor(private changeDetector : ChangeDetectorRef ) {}
dan kemudianSaya harap ini membantu yang lain karena banyak yang telah membantu saya.
sumber
Angular menjalankan perubahan deteksi dan ketika menemukan bahwa beberapa nilai yang telah diteruskan ke komponen anak telah diubah Angular melempar kesalahan:
ExpressionChangedAfterItHasBeenCheckedError
klik untuk lebihUntuk memperbaikinya kita dapat menggunakan
AfterContentChecked
kait siklus hidup dansumber
Dalam kasus saya, saya memiliki masalah ini di file spesifikasi saya, saat menjalankan tes saya.
Saya harus pindah
ngIf
ke[hidden]
untuk
sumber
[hidden]
: talkingdotnet.com/dont-use-hidden-attribute-angularjs-2*ngIf
mengubah DOM, menambah dan menghapus elemen dari halaman, sementara[hidden]
mengubah visibilitas item sambil tidak menghapusnya dari DOM.Ikuti langkah-langkah di bawah ini:
1. Gunakan 'ChangeDetectorRef' dengan mengimpornya dari @ angular / core sebagai berikut:
2. Terapkan dalam constructor () sebagai berikut:
3. Tambahkan metode berikut ke fungsi Anda yang Anda panggil pada suatu acara seperti klik tombol. Jadi terlihat seperti ini:
sumber
Saya menggunakan ng2-carouselamos (Angular 8 & Bootstrap 4)
Di bawah ini memperbaiki masalah saya:
Apa yang saya lakukan:
sumber
Saya menghadapi masalah yang sama ketika nilai berubah di salah satu array di komponen saya. Tetapi alih-alih mendeteksi perubahan pada perubahan nilai, saya mengubah strategi deteksi perubahan komponen menjadi
onPush
(yang akan mendeteksi perubahan pada perubahan objek dan bukan pada perubahan nilai).sumber
Mengacu pada artikel https://blog.angularindepth.com/everything-you-need-to-know-about-the-expressionchangedafterithasbeeckeckederror-error-e3fd9ce7dbb4
Jadi mekanisme di balik deteksi perubahan benar-benar bekerja sedemikian rupa sehingga kedua deteksi perubahan dan pengujian dicerna secara serempak. Itu berarti, jika kita memperbarui properti secara tidak sinkron, nilai-nilai tidak akan diperbarui ketika loop verifikasi sedang berjalan dan kami tidak akan mendapatkan
ExpressionChanged...
kesalahan. Alasan kami mendapatkan kesalahan ini adalah, selama proses verifikasi, Angular melihat nilai yang berbeda dari yang dicatat selama fase deteksi deteksi. Jadi untuk menghindari itu ....1) Gunakan changeDetectorRef
2) gunakan setTimeOut. Ini akan mengeksekusi kode Anda di VM lain sebagai tugas makro. Angular tidak akan melihat perubahan ini selama proses verifikasi dan Anda tidak akan mendapatkan kesalahan itu.
3) Jika Anda benar-benar ingin mengeksekusi kode Anda pada penggunaan VM yang sama seperti
Ini akan membuat tugas mikro. Antrian tugas mikro diproses setelah kode sinkron saat ini selesai dieksekusi sehingga pembaruan ke properti akan terjadi setelah langkah verifikasi.
sumber
@HostBinding
dapat menjadi sumber kesalahan yang membingungkan ini.Sebagai contoh, katakanlah Anda memiliki host berikut yang mengikat komponen
Untuk mempermudah, katakanlah properti ini diperbarui melalui properti input berikut:
Di komponen induk Anda secara sistematis memasukkannya
ngAfterViewInit
Inilah yang terjadi:
carousel
(melalui ViewChild)carousel
sampaingAfterViewInit()
(itu akan menjadi nol)style_groupBG = 'red'
background: red
pada komponen ImageCarousel hostcarousel.style.background
dan tidak cukup pandai untuk mengetahui bahwa ini bukan masalah sehingga membuang pengecualian.Salah satu solusinya adalah dengan memperkenalkan ImageCarousel pembungkus div insider lain dan mengatur warna latar belakangnya, tetapi kemudian Anda tidak mendapatkan beberapa manfaat menggunakan
HostBinding
(seperti memungkinkan orang tua untuk mengontrol batas penuh objek).Solusi yang lebih baik, dalam komponen induk adalah menambahkan detectChanges () setelah pengaturan konfigurasi.
Ini mungkin terlihat cukup jelas seperti ini, dan sangat mirip dengan jawaban lain tetapi ada perbedaan yang halus.
Pertimbangkan kasus di mana Anda tidak menambahkan
@HostBinding
sampai nanti selama pengembangan. Tiba-tiba Anda mendapatkan kesalahan ini dan sepertinya tidak masuk akal.sumber
Inilah pemikiran saya tentang apa yang terjadi. Saya belum membaca dokumentasi tetapi saya yakin ini adalah bagian dari mengapa kesalahan ditampilkan.
Saat menggunakan * ngIf, secara fisik mengubah DOM dengan menambahkan atau menghapus elemen setiap kali kondisinya berubah. Jadi, jika kondisi berubah sebelum ditampilkan (yang sangat mungkin di dunia Angular), kesalahan dilemparkan. Lihat penjelasan di sini antara mode pengembangan dan produksi.
Saat menggunakannya
[hidden]
tidak secara fisik mengubahDOM
tetapi hanya menyembunyikanelement
dari tampilan, kemungkinan besar menggunakanCSS
di belakang. Elemen tersebut masih ada di DOM tetapi tidak terlihat tergantung pada nilai kondisinya. Itu sebabnya kesalahan tidak akan terjadi saat menggunakan[hidden]
.sumber
isProcessing()
melakukan hal yang sama, Anda harus menggunakan!isProcessing()
untuk[hidden]
hidden
tidak "menggunakan CSS di belakang", ini adalah properti HTML biasa. developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/…Untuk masalah saya, saya membaca github - "ExpressionChangedAfterItHasBeenCheckedError ketika mengubah nilai komponen 'non model' di afterViewInit" dan memutuskan untuk menambahkan ngModel
Ini memperbaiki masalah saya, saya harap ini membantu seseorang.
sumber
ngModel
. Dan bisakah Anda menjelaskan mengapa ini harus membantu?Kiat debugging
Kesalahan ini bisa sangat membingungkan, dan mudah untuk membuat asumsi yang salah tentang kapan tepatnya itu terjadi. Saya merasa bermanfaat untuk menambahkan banyak pernyataan debugging seperti ini di seluruh komponen yang terkena dampak di tempat yang tepat. Ini membantu memahami aliran.
Dalam induk, letakkan pernyataan seperti ini (string persis 'EXPRESSIONCHANGED' penting), tetapi selain itu, ini hanya contoh:
Dalam panggilan balik anak / layanan / timer:
Jika Anda menjalankan
detectChanges
secara manual tambahkan logging untuk itu juga:Kemudian di Chrome debugger cukup filter dengan 'EXPRESSIONCHANGES'. Ini akan menunjukkan Anda dengan tepat aliran dan urutan semua yang diatur, dan juga tepat pada titik mana Angular melempar kesalahan.
Anda juga dapat mengklik tautan abu-abu untuk memasukkan breakpoints.
Hal lain yang harus diperhatikan jika Anda memiliki properti dengan nama yang sama di seluruh aplikasi Anda (seperti
style.background
) pastikan Anda mendebug yang menurut Anda - dengan mengaturnya ke nilai warna yang tidak jelas.sumber
Dalam kasus saya, saya memiliki properti async
LoadingService
dengan BehavioralSubjectisLoading
Menggunakan model [tersembunyi] berfungsi, tetapi * ngIf gagal
sumber
Solusi yang bekerja untuk saya menggunakan rxjs
sumber
ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked.
Terjadi ketika perubahan nilai dipicu ketika DOM berubahdelay
membuat kesalahan hilang. Ini bekerja sama dengansetTimeout
.Saya memiliki kesalahan semacam ini di Ionic3 (yang menggunakan Angular 4 sebagai bagian dari tumpukan teknologinya).
Bagi saya itu melakukan ini:
<ion-icon [name]="getFavIconName()"></ion-icon>
Jadi saya mencoba mengubah jenis ikon ion dari a
pin
menjadi aremove-circle
, per mode yang dioperasikan layar.Saya kira saya harus menambahkan
*ngIf
saja.sumber
Masalah saya nyata ketika saya menambahkan
*ngIf
tetapi itu bukan penyebabnya. Kesalahan itu disebabkan oleh mengubah model dalam{{}}
tag kemudian mencoba menampilkan model yang diubah dalam*ngIf
pernyataan di kemudian hari. Ini sebuah contoh:Untuk memperbaiki masalah ini, saya mengubah tempat saya memanggil
changeMyModelValue()
ke tempat yang lebih masuk akal.Dalam situasi saya, saya ingin
changeMyModelValue()
dipanggil setiap kali komponen anak mengubah data. Ini mengharuskan saya membuat dan memancarkan suatu peristiwa dalam komponen anak sehingga orang tua dapat menanganinya (dengan meneleponchangeMyModelValue()
. Lihat https://angular.io/guide/component-interaction#parent-listens-for-child-eventsumber
Saya harap ini membantu seseorang yang datang ke sini: Kami melakukan panggilan layanan
ngOnInit
dengan cara berikut dan menggunakan variabeldisplayMain
untuk mengontrol Pemasangan elemen ke DOM.komponen.ts
dan component.html
sumber
Saya mendapatkan kesalahan ini karena saya menggunakan variabel di component.html yang tidak dideklarasikan di component.ts. Setelah saya menghapus bagian dalam HTML, kesalahan ini hilang.
sumber
Saya mendapatkan kesalahan ini karena saya mengirim tindakan redux dalam modal dan modal tidak dibuka pada waktu itu. Saya mengirim tindakan saat input komponen modal saat. Jadi saya meletakkan setTimeout di sana untuk memastikan bahwa modal dibuka dan kemudian tindakan dipatched.
sumber
Untuk siapa pun yang berjuang dengan ini. Inilah cara untuk men-debug kesalahan ini dengan benar: https://blog.angular-university.io/angular-debugging/
Dalam kasus saya, memang saya menyingkirkan kesalahan ini menggunakan hack [tersembunyi] ini daripada * ngIf ...
Tapi tautan yang saya berikan memungkinkan saya menemukan THE GUILTY * ngIf :)
Nikmati.
sumber
hidden
alih-alihngIf
bukanlah meretas, juga tidak membahas inti masalah sama sekali. Anda hanya menutupi masalah itu.Solusinya ... layanan dan rxjs ... emitor acara dan pengikatan properti baik menggunakan rxjs .. Anda lebih baik menerapkannya sendiri, lebih banyak kontrol, lebih mudah untuk debug. Ingatlah bahwa emitor acara menggunakan rxjs. Sederhananya, buat layanan dan dengan cara yang dapat diamati, mintalah setiap komponen berlangganan pengamat dan berikan nilai baru atau nilai cosume sesuai kebutuhan
sumber