Pertanyaan
Apa cara paling elegan untuk mendapatkan @ViewChild
setelah elemen yang sesuai dalam template ditampilkan?
Di bawah ini adalah contohnya. Juga Plunker tersedia.
Templat:
<div id="layout" *ngIf="display">
<div #contentPlaceholder></div>
</div>
Komponen:
export class AppComponent {
display = false;
@ViewChild('contentPlaceholder', {read: ViewContainerRef}) viewContainerRef;
show() {
this.display = true;
console.log(this.viewContainerRef); // undefined
setTimeout(()=> {
console.log(this.viewContainerRef); // OK
}, 1);
}
}
Saya memiliki komponen dengan isinya disembunyikan secara default. Ketika seseorang memanggil show()
metode itu menjadi terlihat. Namun, sebelum deteksi perubahan Angular 2 selesai, saya tidak bisa merujuk viewContainerRef
. Saya biasanya memasukkan semua tindakan yang diperlukan setTimeout(()=>{},1)
seperti yang ditunjukkan di atas. Apakah ada cara yang lebih benar?
Saya tahu ada opsi dengan ngAfterViewChecked
, tetapi itu menyebabkan terlalu banyak panggilan tidak berguna.
JAWABAN (Plunker)
angular
angular2-changedetection
sinedsem
sumber
sumber
Jawaban:
Gunakan setter untuk ViewChild:
Setter disebut dengan referensi elemen begitu
*ngIf
menjaditrue
.Catatan, untuk Angular 8 Anda harus memastikan untuk mengatur
{ static: false }
, yang merupakan pengaturan default di versi Agnular lainnya:Catatan: jika contentPlaceholder adalah komponen, Anda bisa mengubah ElementRef ke kelas komponen Anda:
sumber
contentPlaceholder
iniElementRef
tidakViewContainerRef
.<div #contentPlaceholder></div>
. Secara teknis Anda dapat memanggilnya secara manual seperti setter lainnyathis.content = someElementRef
tetapi saya tidak mengerti mengapa Anda ingin melakukan itu.Alternatif untuk mengatasi ini adalah menjalankan detektor perubahan secara manual.
Anda pertama-tama menyuntikkan
ChangeDetectorRef
:Kemudian Anda menyebutnya setelah memperbarui variabel yang mengontrol * ngIf
sumber
onInit()
, jadi saya menambahkandetectChanges
sebelum memanggil fungsi anak dan memperbaikinya. (Saya menggunakan jawaban yang diterima dan jawaban ini)8 Sudut
Anda harus menambahkan
{ static: false }
sebagai opsi kedua untuk@ViewChild
. Ini menyebabkan hasil kueri diselesaikan setelah deteksi perubahan berjalan, memungkinkan Anda@ViewChild
untuk diperbarui setelah nilai berubah.Contoh:
Contoh Stackblitz: https://stackblitz.com/edit/angular-d8ezsn
sumber
<mat-horizontal-stepper *ngIf="viewMode === DialogModeEnum['New']" linear #stepper
,@ViewChild('stepper', {static: true}) private stepper: MatStepper;
danthis.changeDetector.detectChanges();
dan itu masih tidak berhasil.Jawaban di atas tidak bekerja untuk saya karena dalam proyek saya, ngIf ada pada elemen input. Saya membutuhkan akses ke atribut nativeElement untuk fokus pada input ketika ngIf benar. Tampaknya tidak ada atribut nativeElement di ViewContainerRef. Inilah yang saya lakukan (mengikuti dokumentasi @ViewChild ):
Saya menggunakan setTimeout sebelum fokus karena ViewChild membutuhkan beberapa detik untuk ditugaskan. Kalau tidak, itu tidak akan ditentukan.
sumber
setTimeout
?I usually wrap all required actions into setTimeout(()=>{},1) as shown above. Is there a more correct way?
Seperti yang disebutkan oleh yang lain, solusi tercepat dan tercepat adalah dengan menggunakan [disembunyikan] daripada * ngIf, dengan cara ini komponen akan dibuat tetapi tidak terlihat, karena Anda dapat memiliki akses ke sana, meskipun itu mungkin bukan yang paling efisien cara.
sumber
Ini bisa berhasil, tetapi saya tidak tahu apakah ini cocok untuk kasus Anda:
sumber
ngAfterViewInit()
alih-alihngOnInit()
. Saya berasumsi bahwaviewContainerRefs
ini sudah diinisialisasi tetapi belum mengandung item. Sepertinya saya ingat ini salah.AfterViewInit
sebenarnya bekerja. Saya telah menghapus semua komentar saya agar tidak membingungkan orang. Ini adalah Plunker yang berfungsi: plnkr.co/edit/myu7qXonmpA2hxxU3SLB?p=previewconst
parameterViewChild
"Trik" cepat lainnya (solusi mudah) adalah hanya menggunakan tag [tersembunyi] alih-alih * ngIf, hanya penting untuk mengetahui bahwa dalam kasus itu Angular membangun objek dan melukisnya di bawah kelas: disembunyikan inilah sebabnya ViewChild bekerja tanpa masalah . Jadi penting untuk diingat bahwa Anda tidak boleh menggunakan tersembunyi pada barang-barang berat atau mahal yang dapat menyebabkan masalah kinerja
sumber
Tujuan saya adalah untuk menghindari metode peretasan yang mengasumsikan sesuatu (misalnya setTimeout) dan saya akhirnya menerapkan solusi yang diterima dengan sedikit rasa RxJS di atas:
Skenario saya: Saya ingin menjalankan aksi pada
@ViewChild
elemen tergantung pada routerqueryParams
. Karena pembungkus*ngIf
menjadi salah sampai permintaan HTTP mengembalikan data, inisialisasi@ViewChild
elemen terjadi dengan penundaan.Bagaimana cara kerjanya:
combineLatest
memancarkan nilai untuk pertama kalinya hanya ketika masing-masing Observables yang disediakan memancarkan nilai pertama sejak saatcombineLatest
itu berlangganan. Subjek sayatabSetInitialized
memancarkan nilai saat@ViewChild
elemen disetel. Dengan itu, saya menunda eksekusi kode di bawahsubscribe
sampai*ngIf
ternyata positif dan@ViewChild
diinisialisasi.Tentu saja jangan lupa berhenti berlangganan di ngOnDestroy, saya melakukannya menggunakan
ngUnsubscribe
Subjek:sumber
Versi yang disederhanakan, saya memiliki masalah yang serupa dengan ini ketika menggunakan Google Maps JS SDK.
Solusi saya adalah untuk mengekstrak
div
danViewChild
ke dalam komponen anak itu sendiri yang ketika digunakan dalam komponen induk dapat disembunyikan / ditampilkan menggunakan*ngIf
.Sebelum
HomePageComponent
TemplatHomePageComponent
KomponenSetelah
MapComponent
TemplatMapComponent
KomponenHomePageComponent
TemplatHomePageComponent
Komponensumber
Dalam kasus saya, saya perlu memuat seluruh modul hanya ketika div ada dalam template, artinya outlet berada di dalam sebuah ngif. Dengan cara ini, setiap sudut mendeteksi elemen #geolocalisationOutlet, ia membuat komponen di dalamnya. Modul ini hanya memuat sekali juga.
sumber
Saya pikir menggunakan penundaan dari lodash sangat masuk akal terutama dalam kasus saya di mana saya
@ViewChild()
berada di dalamasync
pipasumber
Bekerja pada Angular 8 Tidak perlu mengimpor ChangeDector
ngIf memungkinkan Anda untuk tidak memuat elemen dan menghindari menambahkan lebih banyak tekanan ke aplikasi Anda. Inilah cara saya menjalankannya tanpa ChangeDetector
Kemudian ketika saya mengubah nilai ngIf saya menjadi benar, saya akan menggunakan setTimeout seperti ini untuk menunggu hanya untuk siklus perubahan berikutnya:
Ini juga memungkinkan saya untuk menghindari menggunakan perpustakaan atau impor tambahan.
sumber
untuk Angular 8 - campuran pemeriksaan nol dan
@ViewChild
static: false
peretasanuntuk kontrol paging menunggu data async
sumber
Ini berfungsi untuk saya jika saya menggunakan ChangeDetectorRef di Angular 9
sumber