Bagaimana saya harus menggunakan opsi statis baru untuk @ViewChild di Angular 8?

204

Bagaimana saya harus mengkonfigurasi anak tampilan 8 Sudut baru?

@ViewChild('searchText', {read: ElementRef, static: false})
public searchTextInput: ElementRef;

vs.

@ViewChild('searchText', {read: ElementRef, static: true})
public searchTextInput: ElementRef;

Mana yang lebih baik? Kapan saya harus menggunakan static:truevs static:false?

Patrik Laszlo
sumber

Jawaban:

237

Dalam kebanyakan kasus, Anda ingin menggunakannya {static: false}. Menyetelnya seperti ini akan memastikan kecocokan permintaan yang bergantung pada resolusi yang mengikat (seperti arahan struktural *ngIf, etc...) akan ditemukan.

Contoh kapan harus menggunakan static: false:

@Component({
  template: `
    <div *ngIf="showMe" #viewMe>Am I here?</div>
    <button (click)="showMe = !showMe"></button>
  ` 
})
export class ExampleComponent {
  @ViewChild('viewMe', { static: false })
  viewMe?: ElementRef<HTMLElement>; 

  showMe = false;
}

Ini static: falseakan menjadi perilaku fallback default di Angular 9. Baca lebih lanjut di sini dan di sini

The { static: true }pilihan diperkenalkan untuk mendukung menciptakan tertanam pandangan dengan cepat. Ketika Anda membuat tampilan secara dinamis dan ingin mengaksesnya TemplateRef, Anda tidak akan dapat melakukannya ngAfterViewInitkarena akan menyebabkan ExpressionHasChangedAfterCheckedkesalahan. Mengatur flag statis menjadi true akan membuat tampilan Anda di ngOnInit.

Namun:

Dalam kebanyakan kasus lain, praktik terbaik adalah menggunakan {static: false}.

Perlu diketahui juga bahwa { static: false }opsi akan dibuat default di Angular 9. Yang berarti bahwa pengaturan flag statis tidak lagi diperlukan, kecuali jika Anda ingin menggunakan static: trueopsi.

Anda dapat menggunakan ng updateperintah clari sudut untuk secara otomatis meningkatkan basis kode Anda saat ini.

Untuk panduan migrasi dan informasi lebih lanjut tentang ini, Anda dapat memeriksa di sini dan di sini

Apa perbedaan antara permintaan statis dan dinamis?

Opsi statis untuk kueri @ViewChild () dan @ContentChild () menentukan kapan hasil kueri tersedia.

Dengan kueri statis (statis: benar), kueri diselesaikan setelah tampilan dibuat, tetapi sebelum deteksi perubahan berjalan. Hasilnya, bagaimanapun, tidak akan pernah diperbarui untuk mencerminkan perubahan pada pandangan Anda, seperti perubahan ke ngIf dan ngFor blok.

Dengan kueri dinamis (statis: salah), kueri diselesaikan setelah ngAfterViewInit () atau ngAfterContentInit () untuk masing-masing @ViewChild () dan @ContentChild (). Hasilnya akan diperbarui untuk perubahan pada tampilan Anda, seperti perubahan ke ngIf dan ngFor blok.

Poul Kruijt
sumber
Harap perbarui tautan untuk dokumen sudut (diubah setelah rilis) angular.io/api/core/ViewChild#description
Sachin Gupta
2
Saya tidak dapat mengakses instance childView. Dikatakan tidak terdefinisi sepanjang waktu.
Nesan Mano
Bisakah Anda memberikan tautan tentang informasi menghapus opsi statis di Angular 9?
Alex Marinov
@AlexMarinov Saya telah memperbarui jawaban saya untuk membuatnya lebih jelas apa yang akan terjadi di sudut 9. Tautan tentang ini ada di panduan migrasi
Poul Kruijt
1
@ MinhNghĩa jika Anda membuat seluruh komponen di luar template komponen, Anda dapat menggunakan { static: true }, tetapi jika tidak ada kebutuhan langsung untuk memiliki akses ke ViewChild di dalam ngOnInit, Anda harus menggunakan { static: false }.
Poul Kruijt
88

Jadi sebagai aturan praktis Anda dapat mengikuti yang berikut:

  • { static: true }kebutuhan untuk menjadi set ketika Anda ingin mengakses ViewChilddi ngOnInit.

  • { static: false }hanya dapat diakses di ngAfterViewInit. Ini juga yang Anda inginkan ketika Anda memiliki arahan struktural (yaitu *ngIf) pada elemen Anda di template Anda.

dave0688
sumber
2
Catatan: Di Angular 9, flag statis default menjadi false, jadi "semua flag {static: false} dapat dihapus dengan aman". Dokumentasi: angular.io/guide/static-query-migration
Stevethemacguy
17

Dari dokumen sudut

statis - apakah akan menyelesaikan hasil permintaan atau tidak sebelum deteksi berjalan (yaitu, kembalikan hanya hasil statis). Jika opsi ini tidak disediakan, kompiler akan kembali ke perilaku standarnya, yaitu menggunakan hasil kueri untuk menentukan waktu resolusi kueri. Jika ada hasil kueri di dalam tampilan bersarang (mis. * NgIf), kueri akan diselesaikan setelah perubahan deteksi berjalan. Kalau tidak, itu akan diselesaikan sebelum perubahan deteksi berjalan.

Mungkin ide yang lebih baik untuk digunakan static:truejika anak tidak tergantung pada kondisi apa pun. Jika visibilitas elemen berubah, maka static:falsedapat memberikan hasil yang lebih baik.

PS: Karena ini fitur baru, kami mungkin perlu menjalankan benchmark untuk kinerja.

Edit

Seperti yang disebutkan oleh @Massimiliano Sartoretto, github commit dapat memberi Anda lebih banyak wawasan.

Sachin Gupta
sumber
3
Saya akan menambahkan motivasi resmi di balik fitur ini github.com/angular/angular/pull/28810
Massimiliano Sartoretto
2

Datang ke sini karena ViewChild adalah null di ngOnInit setelah memutakhirkan ke Angular 8.

Kueri statis diisi sebelum ngOnInit, sementara kueri dinamis (statis: salah) diisi sesudahnya. Dengan kata lain, jika viewchild sekarang null di ngOnInit setelah Anda menetapkan static: false, Anda harus mempertimbangkan untuk mengubah ke static: true atau pindahkan kode ke ngAfterViewInit.

Lihat https://github.com/angular/angular/blob/master/packages/core/src/view/view.ts#L332-L336

Jawaban lain benar dan menjelaskan mengapa hal ini terjadi: Permintaan bergantung pada arahan struktural, misalnya referensi ViewChild di dalam ngIf, harus dijalankan setelah persyaratan arahan ini telah diselesaikan, yaitu setelah deteksi perubahan. Namun, orang dapat dengan aman menggunakan statis: true dan dengan demikian menyelesaikan pertanyaan sebelum ngOnInit untuk referensi yang tidak diuji. Seandainya kasus khusus ini disebut sebagai pengecualian nol mungkin bisa menjadi cara pertama Anda akan menemui kekhususan ini, seperti bagi saya.

daun mahkota
sumber
1

lihat child @angular 5+ token dua argumen ('nama referensi lokal', statis: false | true)

@ViewChild('nameInput', { static: false }) nameInputRef: ElementRef;

untuk mengetahui perbedaan antara benar dan salah periksa ini

statis - apakah akan menyelesaikan hasil permintaan atau tidak sebelum deteksi berjalan (yaitu, kembalikan hanya hasil statis). Jika opsi ini tidak disediakan, kompiler akan kembali ke perilaku standarnya, yaitu menggunakan hasil kueri untuk menentukan waktu resolusi kueri. Jika ada hasil kueri di dalam tampilan bersarang (mis. * NgIf), kueri akan diselesaikan setelah perubahan deteksi berjalan. Kalau tidak, itu akan diselesaikan sebelum perubahan deteksi berjalan.

Samar Abdallah
sumber
0

Dalam ng8, Anda dapat secara manual mengatur kapan untuk mengakses komponen anak di komponen induk. Ketika Anda mengatur statis ke true, itu berarti komponen induk hanya mendapatkan definisi komponen di onInithook: Misalnya:

 // You got a childComponent which has a ngIf/for tag
ngOnInit(){
  console.log(this.childComponent);
}

ngAfterViewInit(){
  console.log(this.childComponent);
}

Jika statis salah, maka Anda hanya mendapatkan definisi di ngAfterViewInit (), di ngOnInit (), Anda tidak akan terdefinisi.

Tethys Zhang
sumber