Saya memiliki komponen sederhana yang memanggil REST api setiap beberapa detik dan menerima kembali beberapa data JSON. Saya dapat melihat dari pernyataan log saya dan lalu lintas jaringan bahwa data JSON yang dikembalikan berubah, dan model saya sedang diperbarui, namun tampilan tidak berubah.
Komponen saya terlihat seperti:
import {Component, OnInit} from 'angular2/core';
import {RecentDetectionService} from '../services/recentdetection.service';
import {RecentDetection} from '../model/recentdetection';
import {Observable} from 'rxjs/Rx';
@Component({
selector: 'recent-detections',
templateUrl: '/app/components/recentdetection.template.html',
providers: [RecentDetectionService]
})
export class RecentDetectionComponent implements OnInit {
recentDetections: Array<RecentDetection>;
constructor(private recentDetectionService: RecentDetectionService) {
this.recentDetections = new Array<RecentDetection>();
}
getRecentDetections(): void {
this.recentDetectionService.getJsonFromApi()
.subscribe(recent => { this.recentDetections = recent;
console.log(this.recentDetections[0].macAddress) });
}
ngOnInit() {
this.getRecentDetections();
let timer = Observable.timer(2000, 5000);
timer.subscribe(() => this.getRecentDetections());
}
}
Dan pandangan saya terlihat seperti:
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading"><h3>Recently detected</h3></div>
<div class="panel-body">
<p>Recently detected devices</p>
</div>
<!-- Table -->
<table class="table" style="table-layout: fixed; word-wrap: break-word;">
<thead>
<tr>
<th>Id</th>
<th>Vendor</th>
<th>Time</th>
<th>Mac</th>
</tr>
</thead>
<tbody >
<tr *ngFor="#detected of recentDetections">
<td>{{detected.broadcastId}}</td>
<td>{{detected.vendor}}</td>
<td>{{detected.timeStamp | date:'yyyy-MM-dd HH:mm:ss'}}</td>
<td>{{detected.macAddress}}</td>
</tr>
</tbody>
</table>
</div>
Saya bisa melihat dari hasil console.log(this.recentDetections[0].macAddress)
bahwa objek recentDetections sedang diperbarui, tetapi tabel dalam tampilan tidak pernah berubah kecuali saya memuat ulang halaman.
Saya berjuang untuk melihat apa yang saya lakukan salah di sini. Adakah yang bisa membantu?
Jawaban:
Mungkin kode dalam layanan Anda entah bagaimana keluar dari zona Angular. Ini merusak deteksi perubahan. Ini harus bekerja:
Untuk cara lain untuk menjalankan deteksi perubahan, lihat Memicu deteksi perubahan secara manual di Angular
Cara alternatif untuk meminta deteksi perubahan adalah
untuk segera menjalankan deteksi perubahan untuk komponen saat ini dan turunannya
untuk menyertakan komponen saat ini pada saat Angular menjalankan deteksi perubahan
untuk menjalankan deteksi perubahan untuk seluruh aplikasi
sumber
cdRef.detectChanges()
bukanzone.run()
. Ini bisa lebih efisien, karena tidak akan menjalankan deteksi perubahan pada seluruh struktur pohon seperti yangzone.run()
dilakukannya.detectChanges()
jika perubahan yang Anda buat bersifat lokal pada komponen dan turunannya. Pemahaman saya adalah bahwadetectChanges()
akan memeriksa komponen dan keturunannya, tapizone.run()
danApplicationRef.tick()
akan memeriksa seluruh pohon komponen.@Input()
tidak masuk akal atau berhasil.Ini awalnya adalah jawaban di komentar dari @Mark Rajcok, Tapi saya ingin menempatkannya di sini sebagai yang teruji dan berfungsi sebagai solusi menggunakan ChangeDetectorRef , saya melihat poin yang bagus di sini:
Jadi kodenya harus seperti:
Sunting : Menggunakan
.detectChanges()
dalam pelanggan dapat menyebabkan masalah Percobaan untuk menggunakan tampilan yang hancur: detectChangesUntuk mengatasinya Anda perlu
unsubscribe
sebelum Anda menghancurkan komponen tersebut, sehingga kode lengkapnya akan menjadi seperti:sumber
Coba gunakan
@Input() recentDetections: Array<RecentDetection>;
EDIT: Alasan mengapa
@Input()
penting adalah karena Anda ingin mengikat nilai dalam file skrip / javascript ke tampilan (html). Tampilan akan diperbarui sendiri jika nilai yang dideklarasikan dengan@Input()
dekorator diubah. Jika@Input()
atau@Output()
dekorator diubah,ngOnChanges
-peristiwa akan terpicu, dan tampilan akan diperbarui sendiri dengan nilai baru. Anda mungkin mengatakan bahwa@Input()
kehendak mengikat nilai dua arah.cari Input di tautan ini dengan sudut: glosarium untuk informasi lebih lanjut
EDIT: setelah mempelajari lebih lanjut tentang pengembangan Angular 2, saya berpikir bahwa melakukan
@Input()
benar-benar bukanlah solusi, dan seperti yang disebutkan di komentar,Jika Anda melihat jawaban @ Günter, ini adalah solusi yang lebih akurat dan tepat untuk masalah tersebut. Saya akan tetap menyimpan jawaban ini di sini, tetapi harap ikuti jawaban Günter sebagai jawaban yang benar.
sumber
@Input()
kata kunci, dan pengikatan itu memastikan bahwa nilainya diperbarui dalam tampilan. nilai akan menjadi bagian dari peristiwa siklus hidup. Posting ini berisi beberapa informasi lebih lanjut tentang kata@Input()
kunci@Input()
terlibat di sini atau mengapa harus dan pertanyaan tidak memberikan informasi yang cukup. Terima kasih atas kesabaran Anda :)@Input()
lebih merupakan solusi yang menyembunyikan akar masalah. Masalahnya harus terkait dengan zona dan deteksi perubahan.Dalam kasus saya, saya memiliki masalah yang sangat mirip. Saya memperbarui tampilan saya di dalam fungsi yang dipanggil oleh komponen induk, dan di komponen induk, saya lupa menggunakan @ViewChild (NameOfMyChieldComponent). Saya kehilangan setidaknya 3 jam hanya karena kesalahan bodoh ini. yaitu: Saya tidak perlu menggunakan salah satu metode tersebut:
sumber
Alih-alih berurusan dengan zona dan deteksi perubahan - biarkan AsyncPipe menangani kompleksitas. Ini akan menempatkan langganan yang dapat diamati, berhenti berlangganan (untuk mencegah kebocoran memori) dan mengubah deteksi pada bahu Angular.
Ubah kelas Anda untuk membuat observasi, yang akan mengeluarkan hasil dari permintaan baru:
Dan perbarui tampilan Anda untuk menggunakan AsyncPipe:
Ingin menambahkan, bahwa lebih baik membuat layanan dengan metode yang akan mengambil
interval
argumen, dan:exhaustMap
seperti pada kode di atas);sumber