Mengapa komponen dalam plunk sederhana ini
@Component({
selector: 'my-app',
template: `<div>I'm {{message}} </div>`,
})
export class App {
message:string = 'loading :(';
ngAfterViewInit() {
this.updateMessage();
}
updateMessage(){
this.message = 'all done loading :)'
}
}
pelemparan:
PENGECUALIAN: Ekspresi 'Saya {{message}} di App @ 0: 5' telah berubah setelah diperiksa. Nilai sebelumnya: 'Saya memuat :('. Nilai saat ini: 'Saya sudah selesai memuat :)' di [Saya {{message}} di App @ 0: 5]
ketika semua yang saya lakukan adalah memperbarui ikatan sederhana ketika pandangan saya dimulai?
typescript
angular
menggambar moore
sumber
sumber
ExpressionChangedAfterItHasBeenCheckedError
kesalahan menjelaskan perilakunya dengan sangat rinci.ChangeDetectionStrategy
saat menggunakandetectChanges()
stackoverflow.com/questions/39787038/…Jawaban:
Seperti yang dinyatakan oleh drewmoore, solusi yang tepat dalam hal ini adalah secara manual memicu deteksi perubahan untuk komponen saat ini. Ini dilakukan dengan menggunakan
detectChanges()
metodeChangeDetectorRef
objek (diimpor dariangular2/core
), ataumarkForCheck()
metode, yang juga membuat setiap komponen induk diperbarui. Contoh yang relevan :Berikut juga Plunker yang menunjukkan pendekatan ngOnInit , setTimeout , dan enableProdMode untuk berjaga-jaga.
sumber
cdr : any
atau sesuatu seperti itu di bawahmessage
deklarasi. Hanya khawatir saya melewatkan sesuatu?Pertama, perhatikan bahwa pengecualian ini hanya akan dibuang ketika Anda menjalankan aplikasi Anda dalam mode dev (yang merupakan kasus default pada beta-0): Jika Anda menelepon
enableProdMode()
saat bootstrap aplikasi, itu tidak akan dibuang ( lihat plunk yang diperbarui ).Kedua, jangan lakukan itu karena pengecualian ini dilempar karena alasan yang baik: Singkatnya, ketika dalam mode dev, setiap putaran deteksi perubahan segera diikuti oleh putaran kedua yang memverifikasi bahwa tidak ada binding yang berubah sejak akhir yang pertama, karena ini akan menunjukkan bahwa perubahan disebabkan oleh perubahan deteksi itu sendiri.
Dalam plunk Anda, pengikatan
{{message}}
diubah oleh panggilan Anda kesetMessage()
, yang terjadi dingAfterViewInit
hook, yang terjadi sebagai bagian dari giliran deteksi perubahan awal. Itu sendiri tidak bermasalah - masalahnya adalah bahwasetMessage()
perubahan mengikat tetapi tidak memicu putaran baru deteksi perubahan, yang berarti bahwa perubahan ini tidak akan terdeteksi sampai beberapa putaran deteksi perubahan berikutnya dipicu di tempat lain.The takeaway: Apa pun yang mengubah kebutuhan mengikat untuk memicu putaran deteksi perubahan saat itu terjadi.
Perbarui sebagai respons terhadap semua permintaan untuk contoh cara melakukan itu : Solusi @ Tycho berfungsi, seperti yang ditunjukkan tiga metode dalam jawaban yang ditunjukkan @MarkRajcok. Tapi sejujurnya, mereka semua merasa jelek dan salah bagi saya, seperti jenis peretasan yang biasa kami gunakan di ng1.
Yang pasti, ada sesekali keadaan di mana hacks ini tepat, tetapi jika Anda menggunakan mereka pada sesuatu yang lebih dari yang sangat dasar sesekali, itu pertanda bahwa Anda berjuang kerangka bukan sepenuhnya merangkul alam reaktif.
IMHO, yang lebih idiomatik, "Angular2 way" untuk mendekati ini adalah sesuatu di sepanjang baris: ( plunk )
sumber
detectChanges()
.updateMessage
, tidaksetMessage
ngAfterViewChecked()
bekerja untuk saya:sumber
Saya memperbaikinya dengan menambahkan ChangeDetectionStrategy dari inti sudut.
sumber
CheckOnce
( dokumentasi )this.cdr.detectChanges();
setelah apa pun yang Anda coba muat. Karena itu mungkin karena deteksi perubahan tidak memicuTidak bisakah Anda menggunakan
ngOnInit
karena Anda hanya mengubah variabel anggotamessage
?Jika Anda ingin mengakses referensi ke komponen anak
@ViewChild(ChildComponent)
, Anda memang harus menunggungAfterViewInit
.Perbaikan kotor adalah memanggil
updateMessage()
loop acara berikutnya dengan misalnya setTimeout.sumber
Untuk ini saya sudah mencoba jawaban di atas banyak yang tidak berfungsi dalam versi terbaru Angular (6 atau lebih baru)
Saya menggunakan kontrol Material yang memerlukan perubahan setelah pengikatan pertama dilakukan.
Menambahkan jawaban saya, ini membantu beberapa orang memecahkan masalah tertentu.
sumber
Artikel Semua yang perlu Anda ketahui tentang
ExpressionChangedAfterItHasBeenCheckedError
kesalahan menjelaskan perilakunya dengan sangat rinci.Masalah dengan pengaturan Anda adalah bahwa
ngAfterViewInit
kait siklus hidup dijalankan setelah deteksi perubahan diproses pembaruan DOM. Dan Anda secara efektif mengubah properti yang digunakan dalam templat di kait ini yang berarti bahwa DOM perlu dirender ulang:dan ini akan membutuhkan siklus deteksi perubahan lain dan Angular by design hanya menjalankan satu siklus digest.
Anda pada dasarnya memiliki dua alternatif cara memperbaikinya:
perbarui properti secara sinkron baik menggunakan
setTimeout
,Promise.then
atau asynchronous yang dapat diamati yang direferensikan dalam templatelakukan pembaruan properti di sebuah kail sebelum pembaruan DOM - ngOnInit, ngDoCheck, ngAfterContentInit, ngAfterContentChecked.
sumber
Anda hanya perlu memperbarui pesan Anda di hook siklus hidup yang benar, dalam hal ini
ngAfterContentChecked
bukanngAfterViewInit
, karena di ngAfterViewInit cek untuk pesan variabel telah dimulai tetapi belum berakhir.lihat: https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html#!#afterview
jadi kodenya akan adil:
lihat demo kerja di Plunker.
sumber
@ViewChildren()
penghitung berbasis panjang yang dihuni oleh Observable. Ini adalah satu-satunya solusi yang berhasil untuk saya!ngAfterContentChecked
danChangeDetectorRef
dari atas berhasil untuk saya. SaatngAfterContentChecked
dipanggil -this.cdr.detectChanges();
Kesalahan ini terjadi karena nilai yang ada diperbarui segera setelah diinisialisasi. Jadi jika Anda akan memperbarui nilai baru setelah nilai yang ada diberikan di DOM, Maka itu akan berfungsi dengan baik. Seperti disebutkan dalam artikel ini Angular Debugging "Ekspresi telah berubah setelah diperiksa"
misalnya bisa kamu gunakan
}
atau
Seperti yang Anda lihat, saya belum menyebutkan waktu dalam metode setTimeout. Karena itu adalah API yang disediakan browser, bukan JavaScript API, Jadi ini akan berjalan secara terpisah di tumpukan browser dan akan menunggu sampai item tumpukan panggilan selesai.
Bagaimana konsep browser API envokes dijelaskan oleh Philip Roberts di salah satu video Youtube (What the hack is event loop?).
sumber
Anda juga dapat melakukan panggilan ke updateMessage () di Metode ngOnInt () - setidaknya berfungsi untuk saya
Dalam RC1 ini tidak memicu pengecualian
sumber
Anda juga dapat membuat timer menggunakan
Observable.timer
fungsi rxjs , dan kemudian memperbarui pesan di langganan Anda:sumber
Itu melempar kesalahan karena kode Anda diperbarui ketika ngAfterViewInit () dipanggil. Berarti nilai awal Anda berubah ketika ngAfterViewInit terjadi, Jika Anda memanggilnya di ngAfterContentInit () maka itu tidak akan menimbulkan kesalahan.
sumber
Saya tidak bisa mengomentari posting @Biranchi karena saya tidak punya reputasi yang cukup, tetapi itu memperbaiki masalah bagi saya.
Satu hal yang perlu diperhatikan! Jika menambahkan changeDetection: ChangeDetectionStrategy.OnPush pada komponen tidak berfungsi, dan komponen turunannya (komponen bodoh) coba menambahkannya ke induk juga.
Ini memperbaiki bug, tapi saya ingin tahu apa efek sampingnya.
sumber
Saya mendapat kesalahan serupa saat bekerja dengan datatable. Apa yang terjadi adalah ketika Anda menggunakan * ngFor di dalam yang lain * ngFor datatable membuang kesalahan ini karena ia mengganggu siklus perubahan sudut. SO daripada menggunakan datatable di dalam datatable, gunakan satu tabel biasa atau ganti mf.data dengan nama array. Ini berfungsi dengan baik.
sumber
Saya pikir solusi paling sederhana adalah sebagai berikut:
(static working: boolean)
di kelas di mana fungsi ini ada dan setiap kali Anda memanggil fungsi, cukup buat yang mana pun yang Anda suka. Dalam fungsi tersebut, jika nilai bekerja itu benar, maka langsung kembali tanpa melakukan apa-apa. lain, lakukan tugas yang Anda inginkan. Pastikan untuk mengubah variabel ini menjadi false setelah tugas selesai yaitu pada akhir baris kode atau dalam metode berlangganan ketika Anda selesai menetapkan nilai!sumber