Dengan Angular, Anda dapat melakukan apa saja. Atau hampir semuanya. Tetapi kadang-kadang “hampir” yang berbahaya ini mengarah pada fakta bahwa pengembang membuang-buang waktu dengan menciptakan solusi, atau mencoba memahami mengapa sesuatu terjadi, atau mengapa sesuatu tidak berfungsi seperti yang diharapkan.

Penulis artikel yang kami terjemahkan hari ini mengatakan ia ingin berbagi kiat yang akan membantu pengembang Angular menghemat waktu. Dia akan berbicara tentang perangkap Angular, yang dia (dan bukan hanya dia) memiliki kesempatan untuk bertemu.
1 Arahan khusus yang Anda terapkan tidak berfungsi
Jadi, Anda menemukan arahan pihak ketiga yang bagus dan memutuskan untuk menggunakannya dengan elemen standar di templat Angular. Hebat! Mari kita coba lakukan ini:
<span awesomeTooltip="'Tooltip text'"> </span>
Anda memulai aplikasi ... Dan tidak ada yang terjadi. Anda, seperti programmer normal dan berpengalaman lainnya, memeriksa konsol Alat Pengembang Chrome. Dan Anda tidak melihat apa pun di sana. Arahan tidak berfungsi dan Angular diam.
Kemudian beberapa kepala cemerlang dari tim Anda memutuskan untuk menempatkan arahan dalam tanda kurung.
<span [awesomeTooltip]="'Tooltip text'"> </span>
Setelah itu, setelah kehilangan sedikit waktu, kami melihat yang berikut di konsol.
Begini masalahnya: kami hanya lupa mengimpor modul dengan arahanSekarang penyebab masalahnya cukup jelas: kami hanya lupa mengimpor modul direktif ke modul aplikasi Angular.
Ini mengarah pada aturan penting: jangan pernah gunakan arahan tanpa tanda kurung.
Anda dapat bereksperimen dengan arahan di
sini .
2 ViewChild mengembalikan undefined
Misalkan Anda membuat tautan ke elemen entri teks yang dijelaskan dalam templat Angular.
<input type="text" name="fname" #inputTag>
Anda akan pergi, menggunakan fungsi RxJS
fromEvent , untuk membuat aliran ke mana apa yang dimasukkan ke dalam bidang akan jatuh. Untuk melakukan ini, Anda memerlukan tautan ke bidang input, yang dapat diperoleh menggunakan dekorator Angular
ViewChild
:
class SomeComponent implements AfterViewInit { @ViewChild('inputTag') inputTag: ElementRef; ngAfterViewInit(){ const input$ = fromEvent(this.inputTag.nativeElement, 'keyUp') } ... }
Di sini, menggunakan fungsi RxJS
fromEvent
, kami membuat aliran ke mana data yang dimasukkan ke dalam bidang akan jatuh.
Uji kode ini.
KesalahanApa yang terjadi
Bahkan, aturan berikut ini berlaku di sini: jika
ViewChild
mengembalikan yang
undefined
, cari
*ngIf
di templat.
<div *ngIf="someCondition"> <input type="text" name="fname" #inputTag> </div>
Di sini dia adalah pelakunya.
Selain itu, periksa template untuk arahan struktural lain atau
ng-template
atas elemen masalah.
Pertimbangkan kemungkinan solusi untuk masalah ini.
▍Variant untuk memecahkan masalah №1
Anda bisa menyembunyikan elemen template jika tidak membutuhkannya. Dalam hal ini, elemen akan selalu terus ada dan
ViewChild
akan dapat mengembalikan tautan ke sana di kait
ngAfterViewInit
.
<div [hidden]="!someCondition"> <input type="text" name="fname" #inputTag> </div>
▍Variant untuk memecahkan masalah №2
Cara lain untuk mengatasi masalah ini adalah dengan menggunakan setter.
class SomeComponent { @ViewChild('inputTag') set inputTag(input: ElementRef|null) { if(!input) return; this.doSomething(input); } doSomething(input) { const input$ = keysfromEvent(input.nativeElement, 'keyup'); ... } }
Di sini, segera setelah Angular memberikan nilai tertentu ke properti
inputTag
, kami membuat aliran dari data yang dimasukkan di bidang input.
Berikut adalah beberapa sumber daya bermanfaat yang terkait dengan masalah ini:
- Di sini Anda dapat membaca bahwa hasil
ViewChild
di Angular 8 bisa statis dan dinamis. - Jika Anda kesulitan bekerja dengan RxJs - lihat kursus video ini .
Nomor 3 Eksekusi kode ketika memperbarui daftar yang dihasilkan dengan * ngFor (setelah elemen muncul di DOM)
Misalkan Anda memiliki beberapa arahan khusus yang menarik untuk mengatur daftar yang dapat digulir. Anda akan menerapkannya ke daftar yang dibuat menggunakan
*ngFor
Angular
*ngFor
.
<div *ngFor="let item of itemsList; let i = index;" [customScroll] > <p *ngFor="let item of items" class="list-item">{{item}}</p> </div>
Biasanya, dalam kasus seperti itu, ketika memperbarui daftar, Anda perlu memanggil sesuatu seperti
scrollDirective.update
untuk mengkonfigurasi perilaku pengguliran, dengan mempertimbangkan perubahan yang telah terjadi dalam daftar.
Tampaknya ini bisa dilakukan dengan menggunakan pengait
ngOnChanges
:
class SomeComponent implements OnChanges { @Input() itemsList = []; @ViewChild(CustomScrollDirective) scroll: CustomScrollDirective; ngOnChanges(changes) { if (changes.itemsList) { this.scroll.update(); } } ... }
Benar, di sini kita dihadapkan dengan masalah. Pengait dipanggil sebelum browser menampilkan daftar yang diperbarui. Akibatnya, perhitungan ulang parameter direktif untuk menggulir daftar dilakukan dengan tidak benar.
Bagaimana cara melakukan panggilan tepat setelah
*ngFor
selesai bekerja?
Anda dapat melakukan ini dengan mengikuti 3 langkah sederhana ini:
▍Langkah nomor 1
Letakkan tautan ke elemen tempat
*ngFor
(
#listItems
)
#listItems
.
<div [customScroll]> <p *ngFor="let item of items" #listItems>{{item}}</p> </div>
▍Langkah nomor 2
Dapatkan daftar elemen-elemen ini menggunakan dekorator
ViewChildren
Angular. Ini mengembalikan entitas tipe
QueryList
.
▍Langkah nomor 3
Kelas
QueryList
memiliki properti
perubahan hanya baca yang
QueryList
acara setiap kali daftar berubah.
class SomeComponent implements AfterViewInit { @Input() itemsList = []; @ViewChild(CustomScrollDirective) scroll: CustomScrollDirective; @ViewChildren('listItems') listItems: QueryList<any>; private sub: Subscription; ngAfterViewInit() { this.sub = this.listItems.changes.subscribe(() => this.scroll.update()) } ... }
Sekarang masalahnya teratasi.
Di sini Anda dapat bereksperimen dengan contoh yang sesuai.
Nomor 4 Masalah dengan ActivatedRoute.queryParam yang Terjadi Ketika Kueri Dapat Dijalankan Tanpa Parameter
Kode berikut akan membantu kami memahami inti dari masalah ini.
Beberapa fragmen dari kode ini dibuat komentar seperti
#x
. Pertimbangkan mereka:
- Dalam modul utama aplikasi, kami mendefinisikan rute dan menambahkan
RouterModule
sana. Rute dikonfigurasikan sehingga jika rute tidak disediakan dalam URL, kami mengarahkan pengguna ke halaman /home
. - Sebagai komponen untuk mengunduh, kami menentukan dalam modul utama
AppComponent
. AppComponent
menggunakan <router-outlet>
untuk menampilkan komponen rute yang sesuai.- Sekarang yang paling penting. Kami perlu mendapatkan
queryParams
untuk rute dari URL
Misalkan kita mendapat URL berikut:
https:
Dalam hal ini,
queryParams
akan terlihat seperti ini:
{accessToken: 'someTokenSequence'}
Mari kita lihat pekerjaan semua ini di browser.
Menguji aplikasi yang mengimplementasikan sistem peruteanDi sini Anda mungkin memiliki pertanyaan tentang esensi masalah. Kami mendapat parameter, semuanya berfungsi seperti yang diharapkan ...
Lihatlah screenshot browser di atas, dan apa yang ditampilkan di konsol. Di sini Anda dapat melihat bahwa objek
queryParams
dikeluarkan dua kali. Objek pertama kosong, dikeluarkan selama proses inisialisasi router Angular. Hanya setelah itu kita mendapatkan objek yang berisi parameter permintaan (dalam kasus kami -
{accessToken: 'someTokenSequence'}
).
Masalahnya adalah bahwa jika tidak ada parameter permintaan di URL, router tidak akan mengembalikan apa pun. Artinya - setelah mengeluarkan objek kosong pertama, objek kedua, juga kosong, yang bisa menunjukkan tidak adanya parameter, tidak akan dikeluarkan.
Saat menjalankan permintaan tanpa parameter, objek kedua tidak dikeluarkanAkibatnya, ternyata jika kode mengharapkan objek kedua dari mana ia dapat menerima data permintaan, maka itu tidak akan diluncurkan jika tidak ada parameter permintaan di URL.
Bagaimana cara mengatasi masalah ini? Di sini, RxJ dapat membantu kami. Kami akan membuat dua objek yang dapat diamati berdasarkan
ActivatedRoute.queryParams
. Seperti biasa - pertimbangkan solusi langkah demi langkah untuk masalah tersebut.
▍Langkah nomor 1
Objek yang dapat diamati pertama,
paramsInUrl$
, akan
paramsInUrl$
data jika
queryParams
tidak kosong:
export class AppComponent implements OnInit { constructor(private route: ActivatedRoute, private locationService: Location) { } ngOnInit() {
▍Langkah nomor 2
Objek yang dapat diamati kedua,
noParamsInUrl$
, akan
noParamsInUrl$
nilai kosong hanya jika tidak ada parameter permintaan yang ditemukan di URL:
export class AppComponent implements OnInit { title = 'QueryTest'; constructor(private route: ActivatedRoute, private locationService: Location) { } ngOnInit() { ...
▍Langkah nomor 3
Sekarang gabungkan objek yang diamati menggunakan fungsi
gabungan RxJS:
export class AppComponent implements OnInit { title = 'QueryTest'; constructor(private route: ActivatedRoute, private locationService: Location) { } ngOnInit() {
Sekarang
param$
object yang diamati
param$
nilai hanya sekali - terlepas dari apakah sesuatu
queryParams
dalam
queryParams
(objek dengan parameter kueri
queryParams
) atau tidak (objek kosong
queryParams
).
Anda dapat bereksperimen dengan kode ini di
sini .
No. 5. Halaman Lambat
Misalkan Anda memiliki komponen yang menampilkan beberapa data yang diformat:
Komponen ini memecahkan dua masalah:
- Ini menampilkan array elemen (diasumsikan bahwa operasi ini dilakukan sekali). Selain itu, memformat apa yang ditampilkan dengan memanggil metode
formatItem
. - Ini menampilkan koordinat mouse (nilai ini jelas akan sangat sering diperbarui).
Anda tidak mengharapkan komponen ini memiliki masalah kinerja. Karena itu, jalankan uji kinerja hanya untuk mematuhi semua formalitas. Namun, beberapa keanehan muncul selama tes ini.
Banyak panggilan formatItem dan beban CPU yang cukup banyakAda apa? Tetapi kenyataannya adalah bahwa ketika Angular menggambar ulang templat, ia memanggil semua fungsi dari templat (dalam kasus kami, fungsi
formatItem
). Akibatnya, jika ada perhitungan berat yang dilakukan dalam fungsi templat, ini akan membuat prosesor tertekan dan memengaruhi cara pengguna melihat laman terkait.
Bagaimana cara memperbaikinya? Cukup dengan melakukan perhitungan yang dilakukan dalam
formatItem
sebelumnya, dan menampilkan data yang sudah siap di halaman.
Sekarang tes kinerja terlihat jauh lebih baik.
Hanya 6 panggilan formatItem dan beban prosesor yang rendahSekarang aplikasi bekerja lebih baik. Tetapi solusi yang digunakan di sini memiliki beberapa fitur yang tidak selalu menyenangkan:
- Karena kami menampilkan koordinat mouse di templat, acara
mousemove
masih memicu pemeriksaan perubahan. Tapi, karena kita membutuhkan koordinat mouse, kita tidak bisa menyingkirkan ini. - Jika pengendali acara
mousemove
hanya perlu melakukan beberapa perhitungan (yang tidak mempengaruhi apa yang ditampilkan pada halaman), maka untuk mempercepat aplikasi, Anda dapat melakukan hal berikut:
- Anda dapat menggunakan
NgZone.runOutsideOfAngular
di dalam fungsi event handler. Ini mencegah pemeriksaan perubahan dari mulai ketika peristiwa mousemove
(ini hanya akan mempengaruhi penangan ini). - Anda dapat mencegah patch zone.js untuk beberapa acara dengan menggunakan baris kode berikut di polyfills.ts . Ini akan memengaruhi seluruh aplikasi Angular.
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove'];
Jika Anda tertarik pada masalah peningkatan kinerja aplikasi Angular - di
sini , di
sini , di
sini dan di
sini - bahan yang berguna tentang ini.
Ringkasan
Sekarang Anda telah membaca artikel ini, 5 alat baru akan muncul di gudang pengembang Angular Anda yang dengannya Anda dapat memecahkan beberapa masalah umum. Kami harap tips yang Anda temukan di sini membantu Anda menghemat waktu.
Pembaca yang budiman! Apakah Anda tahu sesuatu yang membantu Anda menghemat waktu saat mengembangkan aplikasi Angular?
