Semua Perks, Tanpa Kerumitan: Tutorial Sudut 9

Diterbitkan: 2022-03-11

"Setiap tahun internet rusak," kata pepatah, dan pengembang biasanya harus pergi dan memperbaikinya. Dengan Angular versi 9 yang telah lama ditunggu-tunggu, orang mungkin berpikir ini akan berlaku, dan aplikasi yang dikembangkan pada versi sebelumnya harus melalui proses migrasi besar-besaran.

Tapi bukan itu masalahnya! Tim Angular sepenuhnya mendesain ulang kompilernya, menghasilkan build yang lebih cepat, pengujian yang lebih cepat, ukuran bundel yang lebih kecil, dan yang terpenting, kompatibilitas mundur dengan versi yang lebih lama. Dengan Angular 9, pengembang pada dasarnya mendapatkan semua fasilitas tanpa kerumitan.

Dalam tutorial Angular 9 ini, kita akan membangun aplikasi Angular dari awal. Kami akan menggunakan beberapa fitur Angular 9 terbaru dan membahas peningkatan lainnya di sepanjang jalan.

Tutorial Angular 9: Memulai dengan Aplikasi Angular Baru

Mari kita mulai contoh proyek Angular kita. Pertama, mari kita instal versi terbaru CLI Angular:

 npm install -g @angular/cli

Kami dapat memverifikasi versi Angular CLI dengan menjalankan ng version .

Selanjutnya, mari kita buat aplikasi Angular:

 ng new ng9-app --create-application=false --strict

Kami menggunakan dua argumen dalam perintah ng new kami:

  • --create-application=false akan memberi tahu CLI untuk hanya menghasilkan file ruang kerja. Ini akan membantu kita mengatur kode kita dengan lebih baik ketika kita perlu memiliki lebih dari satu aplikasi dan beberapa perpustakaan.
  • --strict akan menambahkan aturan yang lebih ketat untuk menegakkan lebih banyak pengetikan TypeScript dan kebersihan kode.

Sebagai hasilnya, kami memiliki folder dan file ruang kerja dasar.

Tangkapan layar IDE yang menunjukkan folder ng9-app, yang berisi node_modules, .editorconfig, .gitignore, angular.json, package-lock.json, package.json, README.md, tsconfig.json, dan tslint.json.

Sekarang, mari tambahkan aplikasi baru. Untuk melakukan itu, kita akan menjalankan:

 ng generate application tv-show-rating

Kami akan diminta:

 ? Would you like to share anonymous usage data about this project with the Angular Team at Google under Google's Privacy Policy at https://policies.google.com/privacy? For more details and how to change this setting, see http://angular.io/analytics. No ? Would you like to add Angular routing? Yes ? Which stylesheet format would you like to use? SCSS

Sekarang, jika kita menjalankan ng serve , kita akan melihat aplikasi berjalan dengan perancah awalnya.

Tangkapan layar perancah Angular 9, dengan pemberitahuan bahwa "aplikasi rating acara tv sedang berjalan!" Ada juga tautan ke sumber daya dan langkah selanjutnya.

Jika kita menjalankan ng build --prod , kita dapat melihat daftar file yang dihasilkan.

Tangkapan layar dari keluaran "ng build --prod" Angular 9. Itu dimulai dengan "Membuat bundel ES5 untuk pemuatan diferensial..." Setelah itu selesai, ini mencantumkan beberapa potongan file JavaScript—runtime, polyfill, dan main, masing-masing dengan versi -es2015 dan -es5—dan satu file CSS. Baris terakhir memberikan cap waktu, hash, dan runtime 23.881 milidetik.

Kami memiliki dua versi untuk setiap file. Satu kompatibel dengan browser lawas, dan yang lainnya dikompilasi dengan menargetkan ES2015, yang menggunakan API yang lebih baru dan membutuhkan lebih sedikit polyfill untuk dijalankan di browser.

Satu peningkatan besar dari Angular 9 adalah ukuran bundel. Menurut tim Angular, Anda dapat melihat penurunan hingga 40% untuk aplikasi besar.

Untuk aplikasi yang baru dibuat, ukuran bundel cukup mirip dengan Angular 8, tetapi seiring pertumbuhan aplikasi, Anda akan melihat ukuran bundel menjadi lebih kecil dibandingkan versi sebelumnya.

Fitur lain yang diperkenalkan di Angular 9 adalah kemampuan untuk memperingatkan kita jika salah satu file CSS gaya komponen lebih besar dari ambang batas yang ditentukan.

Tangkapan layar bagian "anggaran" dari file konfigurasi Angular 9 JSON, dengan dua objek dalam larik. Objek pertama memiliki "type" yang disetel ke "initial," "maximumWarning" disetel ke "2mb," dan "maximumError" disetel ke "5mb." Objek kedua memiliki "type" yang disetel ke "anyComponentStyle," "maximumWarning" disetel ke "6kb," dan "maximumError" disetel ke "10kb."

Ini akan membantu kami menangkap impor gaya buruk atau file gaya komponen besar.

Menambahkan Formulir untuk Menilai Acara TV

Selanjutnya, kami akan menambahkan formulir untuk menilai acara TV. Untuk itu, pertama kita akan menginstal bootstrap dan ng-bootstrap :

 npm install bootstrap @ng-bootstrap/ng-bootstrap

Peningkatan lain pada Angular 9 adalah i18n (internasionalisasi). Sebelumnya, pengembang perlu menjalankan build lengkap untuk setiap lokal di aplikasi. Sebagai gantinya, Angular 9 memungkinkan kita membangun aplikasi sekali dan menghasilkan semua file i18n dalam proses pasca-pembuatan, yang secara signifikan mengurangi waktu pembuatan. Karena ng-bootstrap memiliki ketergantungan pada i18n, kami akan menambahkan paket baru ke proyek kami:

 ng add @angular/localize

Selanjutnya, kita akan menambahkan tema Bootstrap ke styles.scss aplikasi kita :

 @import "~bootstrap/scss/bootstrap";

Dan kami akan menyertakan NgbModule dan ReactiveFormsModule di AppModule kami di app.module.ts :

 // ... import { ReactiveFormsModule } from '@angular/forms'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; @NgModule({ imports: [ // ... ReactiveFormsModule, NgbModule ], })

Selanjutnya, kami akan memperbarui app.component.html dengan kisi dasar untuk formulir kami:

 <div class="container"> <div class="row"> <div class="col-6"> </div> </div> </div>

Dan hasilkan komponen formulir:

 ng gc TvRatingForm

Mari perbarui tv-rating-form.component.html dan tambahkan formulir untuk menilai acara TV.

 <form [formGroup]="form" (ngSubmit)="submit()" class="mt-3"> <div class="form-group"> <label>TV SHOW</label> <select class="custom-select" formControlName="tvShow"> <option *ngFor="let tvShow of tvShows" [value]="tvShow.name">{{tvShow.name}}</option> </select> </div> <div class="form-group"> <ngb-rating [max]="5" formControlName="rating"></ngb-rating> </div> <button [disabled]="form.invalid || form.disabled" class="btn btn-primary">OK</button> </form>

Dan tv-rating-form.component.ts akan terlihat seperti ini:

 // ... export class TvRatingFormComponent implements OnInit { tvShows = [ { name: 'Better call Saul!' }, { name: 'Breaking Bad' }, { name: 'Lost' }, { name: 'Mad men' } ]; form = new FormGroup({ tvShow: new FormControl('', Validators.required), rating: new FormControl('', Validators.required), }); submit() { alert(JSON.stringify(this.form.value)); this.form.reset(); } }

Terakhir, mari tambahkan formulir ke app.component.html :

 <!-- ... --> <div class="col-6"> <app-tv-rating-form></app-tv-rating-form> </div>

Pada titik ini, kami memiliki beberapa fungsionalitas UI dasar. Sekarang, jika kita menjalankan ng serve lagi, kita bisa melihatnya beraksi.

Cuplikan layar aplikasi tutorial Angular 9 yang menampilkan formulir berjudul "ACARA TV," dengan daftar tarik-turun yang mencantumkan beberapa judul acara, pengukur bintang, dan tombol OK. Dalam animasi, pengguna memilih acara, memilih peringkat, lalu mengklik tombol OK.

Sebelum kita melanjutkan, mari kita lihat sekilas beberapa fitur Angular 9 baru yang menarik yang ditambahkan untuk membantu debugging. Karena ini adalah tugas yang sangat umum dalam pekerjaan kita sehari-hari, ada baiknya mengetahui apa yang telah berubah untuk membuat hidup kita sedikit lebih mudah.

Men-debug dengan Angular 9 Ivy

Peningkatan besar lainnya yang diperkenalkan di Angular 9 dan Angular Ivy adalah pengalaman debugging. Kompiler sekarang dapat mendeteksi lebih banyak kesalahan dan membuangnya dengan cara yang lebih "dapat dibaca".

Mari kita lihat dalam tindakan. Pertama, kita akan mengaktifkan pemeriksaan template di tsconfig.json :

 { // ... "angularCompilerOptions": { "fullTemplateTypeCheck": true, "strictInjectionParameters": true, "strictTemplates": true } }

Sekarang, jika kita memperbarui array tvShows dan mengganti name menjadi title :

 tvShows = [ { title: 'Better call Saul!' }, { title: 'Breaking Bad' }, { title: 'Lost' }, { title: 'Mad men' } ];

…kita akan mendapatkan error dari compiler.

Tangkapan layar keluaran kompiler Angular 9/Angular Ivy, dengan nama file dan posisi, mengatakan "kesalahan TS2339: Properti 'nama' tidak ada pada tipe '{ title: string; }'." Ini juga menunjukkan baris kode yang dimaksud dan menggarisbawahi referensi, dalam hal ini dalam file tv-rating-form.component.html di mana tvShow.name disebutkan. Setelah itu, referensi ke file HTML ini dilacak ke file TypeScript yang sesuai dan disorot dengan cara yang sama.

Pengecekan jenis ini akan memungkinkan kami untuk mencegah kesalahan ketik dan penggunaan jenis TypeScript yang salah.

Validasi Ivy Sudut untuk @Input()

Validasi bagus lainnya yang kami dapatkan adalah dengan @Input() . Misalnya, kami dapat menambahkan ini ke tv-rating-form.component.ts :

 @Input() title: string;

…dan ikat di app.component.html :

 <app-tv-rating-form [title]="title"></app-tv-rating-form>

…dan kemudian ubah app.component.ts seperti ini:

 // ... export class AppComponent { title = null; }

Jika kita membuat ketiga perubahan ini, kita akan mendapatkan jenis kesalahan lain dari kompiler.

Tangkapan layar keluaran kompiler Angular 9/Angular Ivy, dalam format yang mirip dengan yang sebelumnya, menyoroti app.component.html dengan "kesalahan TS 2322: Ketik 'null' is not assignable to type 'string'."

Jika kita ingin melewatinya, kita dapat menggunakan $any() pada template untuk memberikan nilai ke any dan memperbaiki kesalahan:

 <app-tv-rating-form [title]="$any(title)"></app-tv-rating-form>

Namun, cara yang tepat untuk memperbaikinya adalah dengan membuat title pada formulir dapat dibatalkan:

 @Input() title: string | null ;

ExpressionChangedAfterItHasBeenCheckedError di Angular 9 Ivy

Salah satu kesalahan yang paling ditakuti dalam pengembangan Angular adalah ExpressionChangedAfterItHasBeenCheckedError . Untungnya, Ivy mengeluarkan kesalahan dengan cara yang lebih jelas, membuatnya lebih mudah untuk menemukan dari mana masalahnya berasal.

Jadi, mari kita perkenalkan kesalahan ExpressionChangedAfterItHasBeenCheckedError . Untuk melakukannya, pertama, kami akan membuat layanan:

 ng gs Title

Selanjutnya, kita akan menambahkan BehaviorSubject , dan metode untuk mengakses Observable dan untuk memancarkan nilai baru.

 export class TitleService { private bs = new BehaviorSubject < string > (''); constructor() {} get title$() { return this.bs.asObservable(); } update(title: string) { this.bs.next(title); } }

Setelah itu, kita akan menambahkan ini ke app.component.html :

 <!-- ... --> <div class="col-6"> <h2> {{title$ | async}} </h2> <app-tv-rating-form [title]="title"></app-tv-rating-form> </div>

Dan di app.component.ts , kami akan menyuntikkan TitleService :

 export class AppComponent implements OnInit { // ... title$: Observable < string > ; constructor( private titleSvc: TitleService ) {} ngOnInit() { this.title$ = this.titleSvc.title$; } // ... }

Terakhir, di tv-rating-form.component.ts , kita akan menyuntikkan TitleService dan memperbarui judul AppComponent , yang akan memunculkan kesalahan ExpressionChangedAfterItHasBeenCheckedError .

 // ... constructor( private titleSvc: TitleService ) { } ngOnInit() { this.titleSvc.update('new title!'); }

Sekarang kita dapat melihat detail error di konsol dev browser, dan mengklik app.component.html akan mengarahkan kita ke lokasi error.

Cuplikan layar konsol pengembang browser, menunjukkan pelaporan Angular Ivy tentang kesalahan ExpressionChangedAfterItHasBeenCheckedError. Jejak tumpukan dalam teks merah memberikan kesalahan, bersama dengan nilai sebelumnya dan saat ini, dan petunjuk. Di tengah jejak tumpukan adalah satu-satunya baris yang tidak merujuk ke core.js. Pengguna mengkliknya dan dibawa ke baris app.component.html yang menyebabkan kesalahan.

Kami dapat memperbaiki kesalahan ini dengan membungkus panggilan layanan dengan setTimeout :

 setTimeout(() => { this.titleSvc.update('new title!'); });

Untuk memahami mengapa kesalahan ExpressionChangedAfterItHasBeenCheckedError terjadi dan menjelajahi kemungkinan lain, posting Maxim Koretskyi tentang topik ini layak untuk dibaca.

Angular Ivy memungkinkan kita untuk menampilkan kesalahan dengan cara yang lebih jelas dan membantu menegakkan pengetikan TypeScript dalam kode kita. Di bagian berikut, kita akan membahas beberapa skenario umum di mana kita akan memanfaatkan Ivy dan debugging.

Menulis Tes untuk Aplikasi Angular 9 Kami dengan Komponen Harness

Di Angular 9, API pengujian baru diperkenalkan yang disebut komponen harness . Ide di baliknya adalah untuk menghapus semua tugas yang diperlukan untuk berinteraksi dengan DOM, membuatnya lebih mudah untuk dikerjakan dan lebih stabil untuk dijalankan.

API komponen harness disertakan dalam perpustakaan @angular/cdk , jadi mari kita instal dulu di proyek kita:

 npm install @angular/cdk

Sekarang kita dapat menulis pengujian dan memanfaatkan komponen memanfaatkan. Di tv-rating-form.component.spec.ts , mari siapkan pengujian:

 import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { ReactiveFormsModule } from '@angular/forms'; describe('TvRatingFormComponent', () => { let component: TvRatingFormComponent; let fixture: ComponentFixture < TvRatingFormComponent > ; beforeEach(async (() => { TestBed.configureTestingModule({ imports: [ NgbModule, ReactiveFormsModule ], declarations: [TvRatingFormComponent] }).compileComponents(); })); // ... });

Selanjutnya, mari kita implementasikan ComponentHarness untuk komponen kita. Kita akan membuat dua harness: satu untuk TvRatingForm , dan satu lagi untuk NgbRating . ComponentHarness memerlukan bidang static , hostSelector , yang harus mengambil nilai pemilih komponen.

 // ... import { ComponentHarness, HarnessLoader } from '@angular/cdk/testing'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; class TvRatingFormHarness extends ComponentHarness { static hostSelector = 'app-tv-rating-form'; } class NgbRatingHarness extends ComponentHarness { static hostSelector = 'ngb-rating'; } // ...

Untuk TvRatingFormHarness , kami akan membuat pemilih untuk tombol kirim dan fungsi untuk memicu click . Anda dapat melihat betapa mudahnya menerapkan ini.

 class TvRatingFormHarness extends ComponentHarness { // ... protected getButton = this.locatorFor('button'); async submit() { const button = await this.getButton(); await button.click(); } }

Selanjutnya, kami akan menambahkan metode untuk menetapkan peringkat. Di sini kita menggunakan locatorForAll untuk mencari semua elemen <span> yang mewakili bintang yang dapat diklik pengguna. Fungsi rate hanya mendapatkan semua bintang peringkat yang mungkin dan mengklik bintang yang sesuai dengan nilai yang dikirim.

 class NgbRatingHarness extends ComponentHarness { // ... protected getRatings = this.locatorForAll('span:not(.sr-only)'); async rate(value: number) { const ratings = await this.getRatings(); return ratings[value - 1].click(); } }

Bagian terakhir yang hilang adalah menghubungkan TvRatingFormHarness ke NgbRatingHarness . Untuk melakukannya, kita cukup menambahkan locator pada kelas TvRatingFormHarness .

 class TvRatingFormHarness extends ComponentHarness { // ... getRating = this.locatorFor(NgbRatingHarness); // ... }

Sekarang, mari kita tulis pengujian kita:

 describe('TvRatingFormComponent', () => { // ... it('should pop an alert on submit', async () => { spyOn(window, 'alert'); const select = fixture.debugElement.query(By.css('select')).nativeElement; select.value = 'Lost'; select.dispatchEvent(new Event('change')); fixture.detectChanges(); const harness = await TestbedHarnessEnvironment.harnessForFixture(fixture, TvRatingFormHarness); const rating = await harness.getRating(); await rating.rate(1); await harness.submit(); expect(window.alert).toHaveBeenCalledWith('{"tvShow":"Lost","rating":1}'); }); });

Perhatikan bahwa untuk select kami dalam formulir, kami tidak menerapkan pengaturan nilainya melalui harness. Itu karena API masih tidak mendukung pemilihan opsi. Tapi ini memberi kita kesempatan untuk membandingkan di sini seperti apa interaksi dengan elemen sebelum memanfaatkan komponen.

Satu hal terakhir sebelum kita menjalankan tes. Kami perlu memperbaiki app.component.spec.ts karena kami memperbarui title menjadi null .

 describe('AppComponent', () => { // ... it(`should have as title 'tv-show-rating'`, () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.componentInstance; expect(app.title).toEqual(null); }); });

Sekarang, ketika kami menjalankan ng test , pengujian kami lulus.

Tangkapan layar Karma menjalankan tes di aplikasi Angular 9 kami. Ini menunjukkan "Ran 2 dari 6 spesifikasi" dengan pesan "Tidak lengkap: fit() atau fdescribe() ditemukan, 2 spesifikasi, 0 kegagalan, diacak dengan seed 69573." Dua tes TvRatingFormComponent disorot. Tiga pengujian AppComponent dan satu pengujian TitleService semuanya berwarna abu-abu.

Kembali ke Aplikasi Contoh Angular 9 Kami: Menyimpan Data dalam Basis Data

Mari selesaikan tutorial Angular 9 kita dengan menambahkan koneksi ke Firestore dan menyimpan peringkat dalam database.

Untuk melakukan itu, kita perlu membuat Proyek Firebase. Kemudian, kita akan menginstal dependensi yang diperlukan.

 npm install @angular/fire firebase

Dalam pengaturan proyek Firebase Console, kita akan mendapatkan konfigurasinya dan menambahkannya ke environment.ts dan environment.prod.ts :

 export const environment = { // ... firebase: { apiKey: '{your-api-key}', authDomain: '{your-project-id}.firebaseapp.com', databaseURL: 'https://{your-project-id}.firebaseio.com', projectId: '{your-project-id}', storageBucket: '{your-project-id}.appspot.com', messagingSenderId: '{your-messaging-id}', appId: '{your-app-id}' } };

Setelah itu, kami akan mengimpor modul yang diperlukan di app.module.ts :

 import { AngularFireModule } from '@angular/fire'; import { AngularFirestoreModule } from '@angular/fire/firestore'; import { environment } from '../environments/environment'; @NgModule({ // ... imports: [ // ... AngularFireModule.initializeApp(environment.firebase), AngularFirestoreModule, ], // ... })

Selanjutnya, di tv-rating-form.component.ts , kami akan menyuntikkan layanan AngularFirestore dan menyimpan peringkat baru pada pengiriman formulir:

 import { AngularFirestore } from '@angular/fire/firestore'; export class TvRatingFormComponent implements OnInit { constructor( // ... private af: AngularFirestore, ) { } async submit(event: any) { this.form.disable(); await this.af.collection('ratings').add(this.form.value); this.form.enable(); this.form.reset(); } } 

Cuplikan layar aplikasi tutorial Angular 9 yang menampilkan formulir berjudul "ACARA TV" di bawah judul halaman yang lebih besar "judul baru!" Sekali lagi, ia memiliki daftar dropdown beberapa judul acara, meteran bintang, dan tombol OK, dan sekali lagi pengguna memilih acara, memilih peringkat, dan kemudian mengklik tombol OK.

Sekarang, ketika kita pergi ke Firebase Console, kita akan melihat item yang baru dibuat.

Tangkapan layar dari Firebase Console. Di kolom kiri adalah joaq-lab dengan beberapa koleksi: peserta, balapan, peringkat, pengujian, dan pengguna. Item peringkat dipilih dan ditampilkan di kolom tengah dengan ID yang dipilih—ini satu-satunya dokumen. Kolom kanan menunjukkan dua bidang: "rating" disetel ke 4, dan "tvShow" disetel ke "Orang gila."

Terakhir, mari daftarkan semua peringkat ke dalam AppComponent . Untuk melakukan itu, di app.component.ts , kita akan mendapatkan data dari koleksi:

 import { AngularFirestore } from '@angular/fire/firestore'; export class AppComponent implements OnInit { // ... ratings$: Observable<any>; constructor( // ... private af: AngularFirestore ) { } ngOnInit() { // ... this.ratings$ = this.af.collection('ratings').valueChanges(); } }

…dan di app.component.html , kami akan menambahkan daftar peringkat:

 <div class="container"> <div class="row"> // ... <div class="col-6"> <div> <p *ngFor="let rating of ratings$ | async"> {{rating.tvShow}} ({{rating.rating}}) </p> </div> </div> </div> </div>

Seperti inilah tampilan aplikasi tutorial Angular 9 kami ketika semuanya disatukan.

Cuplikan layar aplikasi tutorial Angular 9 yang menampilkan formulir berjudul "ACARA TV" di bawah judul halaman yang lebih besar "judul baru!" Sekali lagi, ia memiliki daftar dropdown beberapa judul acara, meteran bintang, dan tombol OK. Kali ini, kolom sebelah kanan sudah mencantumkan "Orang gila (4)," dan pengguna menilai Kalah dengan tiga bintang, diikuti oleh "Orang gila" lagi dengan empat bintang. Kolom sebelah kanan tetap diurutkan menurut abjad setelah kedua peringkat baru.

Angular 9 dan Angular Ivy: Pengembangan Lebih Baik, Aplikasi Lebih Baik, dan Kompatibilitas Lebih Baik

Dalam tutorial Angular 9 ini, kita telah membahas pembuatan formulir dasar, menyimpan data ke Firebase, dan mengambil item darinya.

Sepanjang jalan, kami melihat peningkatan dan fitur baru mana yang disertakan pada Angular 9 dan Angular Ivy. Untuk daftar lengkapnya, Anda dapat memeriksa posting rilis terbaru resmi blog Angular.


Lencana Mitra Google Cloud.

Sebagai Partner Google Cloud, para ahli Toptal bersertifikasi Google tersedia untuk perusahaan sesuai permintaan untuk proyek terpenting mereka.