Pengenalan bentuk di sudut 4: menulis validator bentuk kustom
() translation by (you can also view the original English article)
Ini adalah bagian ketiga dari seri menciptakan bentuk di sudut. Dalam tutorial pertama dua, kami menggunakan sudut di template berbasis dan berbasis model pendekatan untuk membuat bentuk. Namun, sementara merinci kedua pendekatan, ada sesuatu yang kami tidak menutupi — kustom validator fungsi. Tutorial ini akan mencakup segala sesuatu yang perlu Anda ketahui tentang menulis validator kustom yang memenuhi kebutuhan Anda.
Prasyarat
Anda tidak perlu mengikuti bagian satu atau dua dari seri ini untuk bagian ketiga masuk akal. Namun, jika Anda sama sekali baru untuk bentuk-bentuk di sudut, Anda harus kepala ke tutorial pertama dari seri ini dan mulai dari sana.
Jika tidak, ambil salinan kode ini dari repo GitHub kami dan menggunakannya sebagai titik awal.
Built-in validator
Sudut tidak menawarkan sebuah perpustakaan besar built-in validator. Pada sudut 4, kami memiliki validator populer berikut di sudut:
- diperlukan
- minlength
- maxlength
- pola
Ada sebenarnya sedikit lebih, dan Anda dapat melihat daftar lengkap di dokumentasi sudut.
Kita dapat menggunakan validator built-in di atas dalam dua cara:
1. sebagai pedoman dalam template berbasis bentuk.
1 |
<input name="fullName" ngModel required> |
2. sebagai validator dalam konstruktor FormControl dalam bentuk berbasis model.
1 |
name = new FormControl('', Validators.required) |
Jika sintaks di atas tidak masuk akal, mengikuti tutorial saya sebelumnya pada bangunan signup membentuk menggunakan pendekatan berbasis template atau pendekatan berbasis model dan kemudian turun kembali!
Built-in bentuk validator tidak mencakup semua validasi menggunakan kasus-kasus yang mungkin diperlukan dalam aplikasi dunia nyata. Misalnya, formulir pendaftaran mungkin perlu memeriksa apakah nilai-nilai sandi dan konfirmasi sandi bidang kontrol sama dan menampilkan pesan kesalahan jika mereka tidak cocok. Sebuah validator bahwa blacklist email dari domain tertentu adalah contoh umum yang lain.
Di sini adalah fakta: Template berbasis bentuk yang hanya berbasis model bentuk di bawah. Dalam template berbasis bentuk, kita membiarkan template mengurus penciptaan model bagi kita. Pertanyaan yang jelas sekarang adalah, bagaimana Anda melampirkan sebuah validator ke bentuk?
Validator adalah hanya fungsi. Dalam bentuk berbasis model, melampirkan validator FormControl sangatlah mudah. Dalam template berbasis bentuk, namun, ada sedikit lebih banyak pekerjaan untuk dilakukan. Selain validator fungsi, Anda akan perlu untuk menulis petunjuk untuk validator dan membuat instance dari direktif dalam template.
Menyelam ke dalam rincian
Meskipun ini telah sudah dibahas, kita akan pergi melalui rekap cepat kode untuk formulir pendaftaran. Pertama, di sini adalah pendekatan yang reaktif.
App/signup-form/signup-form.Component.TS
1 |
// Use the formbuilder to build the Form model
|
2 |
this.signupForm = this.fb.group({ |
3 |
email: ['',[Validators.required, |
4 |
Validators.pattern('[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,3}$')]], |
5 |
password: this.fb.group({ |
6 |
pwd: ['', [Validators.required, |
7 |
Validators.minLength(8)]], |
8 |
confirmPwd: ['', [Validators.required, |
9 |
Validators.minLength(8) |
10 |
]]
|
11 |
}, { validator: PasswordMatch }), |
12 |
gender: ['', Validators.required], |
13 |
})
|
FormBuilder adalah gula sintaks yang menciptakan contoh FormGroup dan FormControl. FormControl trek nilai dan status validasi elemen bentuk individu. FormGroup, di sisi lain, terdiri dari sekelompok FormControl contoh, dan trek nilai dan keabsahan seluruh kelompok.
Berikut adalah struktur yang kita telah mengikuti:
1 |
FormGroup -> 'signupForm' |
2 |
FormControl -> 'email' |
3 |
FormGroup -> 'password' |
4 |
FormControl -> 'pwd' |
5 |
FormControl -> 'confirmPwd' |
6 |
FormControl -> 'gender' |
7 |
Tergantung pada persyaratan, kita dapat melampirkan sebuah validator FormControl atau FormGroup. Email daftar hitam validator akan memerlukannya untuk menjadi melekat contoh FormControl email.
Namun, untuk lebih kompleks validasi yang mana beberapa bidang kontrol harus dibandingkan dan divalidasi, itu adalah ide yang lebih baik untuk menambah logika validasi orangtua FormGroup. Seperti yang Anda lihat, password baru FormGroup sendiri, dan hal ini membuat mudah bagi kita untuk menulis validator yang memeriksa kesetaraan pwd dan confirmPwd.
Untuk template berbasis bentuk, semua logika itu masuk ke dalam HTML template, dan berikut ini adalah contoh:
App/signup-form/signup-form.Component.html
1 |
<form novalidate |
2 |
(ngSubmit)="onFormSubmit(signupForm)" |
3 |
#signupForm="ngForm"> |
4 |
|
5 |
<!-- Email input block -->
|
6 |
<input type="text" |
7 |
[ngModel] = "user.email" name="email" |
8 |
pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,3}$" |
9 |
required> |
10 |
|
11 |
<!-- Password block -->
|
12 |
<div ngModelGroup="password"> |
13 |
<input type="password" |
14 |
ngModel name="pwd" |
15 |
minlength ="8" required |
16 |
>
|
17 |
<input type="password" class="form-control" |
18 |
ngModel name="confirmPwd" |
19 |
>
|
20 |
|
21 |
</div>
|
22 |
|
23 |
... |
24 |
|
25 |
<!-- Select Gender block -->
|
26 |
<select id="select" class="form-control" |
27 |
[ngModel] = "user.gender" name = "gender" |
28 |
required> |
29 |
|
30 |
</select>
|
31 |
</form>
|
ngModel menciptakan sebuah instance dari FormControl dan mengikat untuk kontrol elemen form. Demikian pula, ngModelGroup menciptakan dan mengikat sebuah instance FormGroup sebuah elemen DOM. Mereka berbagi sama model domain struktur yang dibahas di atas.
Hal ini juga menarik untuk dicatat bahwa FormControl, FormGroup, dan FormArray memperpanjang kelas AbstractControl. Apa ini berarti adalah bahwa kelas AbstractControl bertanggung jawab untuk melacak nilai-nilai objek formulir, memvalidasi mereka, dan menyalakan hal-hal lain seperti metode murni, kotor dan menyentuh.
Sekarang bahwa kita berkenalan dengan kedua bentuk teknik, mari kita menulis validator kustom kami pertama.
Kustom Validator fungsi untuk bentuk-bentuk berbasis Model
Validator adalah fungsi yang mengambil contoh FormControl FormGroup sebagai masukan dan kembali berupa null atau objek kesalahan. Null dikembalikan saat validasi berhasil, dan jika tidak, objek error dilemparkan. Berikut ini adalah versi yang sangat dasar fungsi validasi.
App/password-match.ts
1 |
import { FormGroup } from '@angular/forms'; |
2 |
export function passwordMatch( |
3 |
control: FormGroup):{[key: string]: boolean} { |
4 |
|
5 |
}
|
Aku telah menyatakan fungsi yang menerima sebuah instance dari FormGroup sebagai masukan. Mengembalikan sebuah objek dengan kunci dari tipe string dan nilai true/false. Hal ini sehingga kita dapat kembali kesalahan objek form dibawah ini:
1 |
{
|
2 |
mismatch: true |
3 |
}
|
Selanjutnya, kita perlu untuk mendapatkan nilai pwd dan confirmPwd contoh FormControl. Aku akan menggunakan control.get() untuk mengambil nilai-nilai mereka.
1 |
export function passwordMatch |
2 |
(control: FormGroup):{[key: string]: boolean} { |
3 |
|
4 |
//Grab pwd and confirmPwd using control.get
|
5 |
const pwd = control.get('pwd'); |
6 |
const confirmPwd = control.get('confirmPwd'); |
7 |
|
8 |
}
|
Sekarang kita perlu membuat perbandingan dan kemudian kembali berupa null atau objek kesalahan.
App/password-match.ts
1 |
import { AbstractControl } from '@angular/forms'; |
2 |
export function passwordMatch |
3 |
(control: AbstractControl):{[key: string]: boolean} { |
4 |
|
5 |
//Grab pwd and confirmPwd using control.get
|
6 |
const pwd = control.get('pwd'); |
7 |
const confirmPwd = control.get('confirmPwd'); |
8 |
|
9 |
// If FormControl objects don't exist, return null
|
10 |
if (!pwd || !confirmPwd) return null; |
11 |
|
12 |
//If they are indeed equal, return null
|
13 |
if (pwd.value === confirmPwd.value) { |
14 |
return null; |
15 |
}
|
16 |
//Else return false
|
17 |
return { |
18 |
mismatch: true }; |
19 |
}
|
Mengapa Apakah mengganti FormGroup dengan AbstractControl? Seperti Anda ketahui, AbstractControl adalah ibu dari semua bentuk * kelas, dan ini memberi Anda lebih banyak kontrol atas bentuk kontrol objek. Ini memiliki manfaat tambahan bahwa hal itu membuat kode validasi kami lebih konsisten.
Impor fungsi passwordMatch dalam komponen SignupForm dan menyatakan hal itu sebagai sebuah validator misalnya FormGroup sandi.
App/password-match.ts
1 |
import { passwordMatch } from './../password-match'; |
2 |
.
|
3 |
.
|
4 |
.
|
5 |
|
6 |
export class SignupFormComponent implements OnInit { |
7 |
|
8 |
ngOnInit() { |
9 |
|
10 |
|
11 |
// Use the formbuilder to build the Form model
|
12 |
this.signupForm = this.fb.group({ |
13 |
...
|
14 |
password: this.fb.group({ |
15 |
pwd: ['', [Validators.required, |
16 |
Validators.minLength(8)]], |
17 |
confirmPwd: ['', [Validators.required, |
18 |
Validators.minLength(8) |
19 |
]]
|
20 |
}, { validator: passwordMatch }), |
21 |
...
|
22 |
})
|
23 |
|
24 |
}
|
25 |
}
|
Menampilkan kesalahan
Jika Anda melakukan segala sesuatu yang benar, password.errors?. ketidakcocokan akan menjadi kenyataan setiap kali nilai bidang kedua tidak sesuai.
1 |
{{ password.errors?.mismatch } json }} |
Meskipun ada cara-cara alternatif untuk menampilkan kesalahan, aku akan menggunakan direktif ngIf untuk menentukan apakah pesan kesalahan harus ditampilkan atau tidak.
Pertama, aku akan menggunakan ngIf untuk melihat apakah password valid.
1 |
<!-- Password error block -->
|
2 |
<div *ngIf="(password.invalid && password.touched)"> |
3 |
|
4 |
</div>
|
Kami menggunakan password.touched untuk memastikan bahwa pengguna tidak disambut dengan kesalahan bahkan sebelum tombol ditekan.
Selanjutnya, saya akan menggunakan ngIf = "ekspresi; kemudian b lain"sintaks untuk menampilkan kesalahan yang tepat.
App/signup-form/signup-form.Component.html
1 |
<ng-container *ngIf="password.errors?.mismatch; |
2 |
then first else second"> </ng-container> |
3 |
|
4 |
<ng-template #first> |
5 |
Password do not match </ng-template>
|
6 |
|
7 |
<ng-template #second> |
8 |
Password needs to be more than 8 characters |
9 |
</ng-template>
|
Di sana Anda memilikinya, model kerja validator yang memeriksa sandi kesetaraan.
Demo untuk kustom validator dalam bentuk berbasis Model
Kustom Validator direktif untuk Template berbasis bentuk
Kita akan menggunakan fungsi validator yang sama bahwa kita diciptakan untuk formulir berbasis model sebelumnya. Namun, kita tidak memiliki akses langsung ke contoh FormControl FormGroup dalam bentuk template berbasis. Berikut adalah hal-hal yang perlu Anda lakukan untuk membuat validator bekerja:
- Membuat PasswordMatchDirective yang berfungsi sebagai pembungkus di sekeliling passwordMatch validator fungsi. Kami akan mendaftar direktif sebagai sebuah validator yang menggunakan penyedia NG_VALIDATORS. Lebih lanjut tentang ini nanti.
- Melampirkan direktif template bentuk kontrol.
Mari kita menulis direktif pertama. Berikut adalah apa yang tampak seperti arahan di sudut:
App/password-match.ts
1 |
import { AbstractControl } from '@angular/forms'; |
2 |
|
3 |
export function passwordMatch |
4 |
(control: AbstractControl):{[key: string]: boolean} { |
5 |
|
6 |
//Grab pwd and confirmPwd using control.get
|
7 |
const pwd = control.get('pwd'); |
8 |
const confirmPwd = control.get('confirmPwd'); |
9 |
|
10 |
// If FormControl objects don't exist, return null
|
11 |
if (!pwd || !confirmPwd) return null; |
12 |
|
13 |
//If they are indeed equal, return null
|
14 |
if (pwd.value === confirmPwd.value) { |
15 |
return null; |
16 |
}
|
17 |
//Else return false
|
18 |
return { |
19 |
mismatch: true }; |
20 |
}
|
21 |
|
22 |
|
23 |
//PasswordMatchDirective
|
24 |
@Directive({ |
25 |
selector: '', |
26 |
providers: [ |
27 |
|
28 |
]
|
29 |
})
|
30 |
|
31 |
export class PasswordMatchDirective { |
32 |
}
|
Dekorator @Directive digunakan untuk menandai kelas sebagai direktif sudut. It menerima objek sebagai argumen yang menentukan konfigurasi direktif meta-data seperti penyeleksi yang direktif harus terpasang, dan daftar penyedia untuk diinjeksikan, dll. Mari kita mengisi direktif meta-data:
App/password-match.ts
1 |
@Directive({ |
2 |
selector: '[passwordMatch][ngModelGroup]', //1 |
3 |
providers: [ //2 |
4 |
{
|
5 |
provide: NG_VALIDATORS, |
6 |
useValue: passwordMatch, |
7 |
multi: true |
8 |
}
|
9 |
]
|
10 |
})
|
11 |
|
12 |
export class PasswordMatchDirective { |
13 |
}
|
- Direktif sekarang melekat pada semua kontrol masukan yang memiliki atribut ngModelGroup dan passwordMatch.
- Kami memperluas validator built-in yang menggunakan penyedia NG_VALIDATORS. Seperti yang disebutkan sebelumnya, NG_VALIDATORS adalah penyedia yang memiliki koleksi yang extensible validator. Fungsi passwordMatch yang kita buat sebelumnya dideklarasikan sebagai ketergantungan. Multi: true set penyedia ini menjadi penyedia yang multi. Apakah ini berarti bahwa kami akan menambahkan koleksi yang ada validator yang disediakan oleh NG_VALIDATORS.
Sekarang, tambahkan direktif ke array Deklarasi di ngModule.
App/App.module.TS
1 |
...
|
2 |
import {PasswordMatchDirective} from './password-match'; |
3 |
|
4 |
@NgModule({ |
5 |
declarations: [ |
6 |
AppComponent, |
7 |
SignupFormComponent, |
8 |
PasswordMatchDirective
|
9 |
],
|
10 |
imports: [ |
11 |
BrowserModule, |
12 |
FormsModule
|
13 |
],
|
14 |
providers: [], |
15 |
bootstrap: [AppComponent] |
16 |
})
|
17 |
export class AppModule { } |
Menampilkan pesan kesalahan
Untuk menampilkan pesan error validasi, aku akan menggunakan template yang sama bahwa kita diciptakan untuk bentuk berbasis model.
1 |
<!-- Password error block -->
|
2 |
<div *ngIf="(userPassword.invalid && userPassword.touched)"> |
3 |
|
4 |
<ng-container *ngIf="userPassword.errors?.mismatch; |
5 |
then first else second"> |
6 |
</ng-container>
|
7 |
<ng-template #first> Password do not match </ng-template> |
8 |
|
9 |
<ng-template #second> |
10 |
Password needs to be more than 8 characters |
11 |
</ng-template>
|
12 |
</div>
|
13 |
Demo untuk kustom validator dalam bentuk Template berbasis
Kesimpulan
Dalam tutorial ini, kita belajar tentang menciptakan kustom sudut validator bagi bentuk-bentuk dalam sudut.
Validator adalah fungsi yang mengembalikan null atau objek kesalahan. Dalam bentuk berbasis model, kita harus melampirkan validator ke instance FormControl FormGroup, dan hanya itu. Prosedur ini sedikit lebih rumit dalam bentuk template berbasis karena kami perlu untuk membuat arahan di atas validator fungsi.
Jika Anda tertarik untuk terus belajar lebih banyak tentang JavaScript, ingatlah untuk memeriksa apa yang kita miliki di pasar Envato.
Saya berharap bahwa Anda menikmati seri ini bentuk di sudut. Saya akan senang mendengar pikiran Anda. Berbagi melalui komentar.