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 ViewChilddi 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 RouterModulesana. 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.
- AppComponentmenggunakan- <router-outlet>untuk menampilkan komponen rute yang sesuai.
- Sekarang yang paling penting. Kami perlu mendapatkan queryParamsuntuk 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 mousemovemasih memicu pemeriksaan perubahan. Tapi, karena kita membutuhkan koordinat mouse, kita tidak bisa menyingkirkan ini.
- Jika pengendali acara mousemovehanya 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.runOutsideOfAngulardi dalam fungsi event handler. Ini mencegah pemeriksaan perubahan dari mulai ketika peristiwamousemove(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?
