在 Angular2 中實(shí)現(xiàn)自定義校驗(yàn)指令(確認(rèn)密碼)的方法
我們會在本文中探索 Angular 2 內(nèi)建的自定義驗(yàn)證。
# 介紹
Angular 2 原生就支持一些有用的驗(yàn)證器:
- required: 驗(yàn)證字段必須存在
- minlength: 驗(yàn)證字段值的最小長度有效
- maxlength: 驗(yàn)證字段值的最大長度有效
- pattern: 驗(yàn)證輸入的值是否匹配給定的模板,比如 email
我們會基于下面的接口創(chuàng)建一個(gè)表單來獲取用戶信息。
// user.interface.ts
export interface User {
username: string; // required, must be 5-8 characters
email: string; // required, must be valid email format
password: string; // required, value must be equal to confirm password.
confirmPassword: string; // required, value must be equal to password.
}
需求
僅在字段數(shù)據(jù)不正確或提交表單的時(shí)候,為每個(gè)字段 顯示錯(cuò)誤消息 。
UI 展示:
# App 配置
這是我們的文件結(jié)構(gòu):
|- app/ |- app.component.html |- app.component.ts |- app.module.ts |- equal-validator.directive.ts |- main.ts |- user.interface.ts |- index.html |- styles.css |- tsconfig.json
為了使用新的表單模塊,我們需要用 npm install @ angular/forms 指令調(diào)用 npm 包,并在應(yīng)用程序模塊中導(dǎo)入最新的表單模塊。
$ npm install @angular/forms --save
下面是我們應(yīng)用程序的 app.module.ts 模塊:
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
@NgModule({
imports: [ BrowserModule, FormsModule ], // import forms module here
declarations: [ AppComponent ],
bootstrap: [ AppComponent ],
})
export class AppModule { }
# App 組件
讓我們繼續(xù)創(chuàng)建 App 組件。
// app.component.ts
import { Component, OnInit } from '@angular/core';
import { User } from './user.interface';
@Component({
moduleId: module.id,
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.css']
})
export class AppComponent implements OnInit {
public user: User;
ngOnInit() {
// initialize model here
this.user = {
username: '',
email: '',
password: '',
confirmPassword: ''
}
}
save(model: User, isValid: boolean) {
// 調(diào)用API保存customer
console.log(model, isValid);
}
}
# HTML 視圖
這是我們的 HTML 視圖的樣子。
<!-- app.component.html --> <div> <h1>Add user</h1> <form #f="ngForm" novalidate (ngSubmit)="save(f.value, f.valid)"> <!-- 我們將把驗(yàn)證的字段放在這里 --> <button type="submit" [disabled]="!myForm.valid">Submit</button> </form> </div>
現(xiàn)在來一個(gè)個(gè)添加控件。
用戶名
需求: 必填,長度在 5-8 個(gè)字符之間
<!-- app.component.html -->
...
<div>
<label>Username</label>
<input type="text" name="username" [ngModel]="user.username"
required minlength="5" maxlength="8" #username="ngModel">
<small [hidden]="username.valid || (username.pristine && !f.submitted)">
Username is required (minimum 5 characters).
</small>
</div>
<pre *ngIf="username.errors">{{ username.errors | json }}</pre>
...
required、minlength、maxlength 都是內(nèi)置的驗(yàn)證器,所以很容易使用。
我們只會在用戶名無效、獲得焦點(diǎn)和提交表單的情況下顯示錯(cuò)誤消息。最后一條的 pre 標(biāo)簽在開發(fā)過程中對調(diào)試很有用。它會顯示字段的所有驗(yàn)證錯(cuò)誤。
電子郵件地址
需求: 必填,必須是有效的電子郵件地址格式
<!-- app.component.html --> ... <div> <label>Email</label> <input type="email" name="email" [ngModel]="user.email" required pattern="^[a-zA-Z0–9_.+-]+@[a-zA-Z0–9-]+.[a-zA-Z0–9-.]+$" #email="ngModel" > <small [hidden]="email.valid || (email.pristine && !f.submitted)"> Email is required and format should be <i>john@doe.com</i>. </small> </div> ...
我們把 email 設(shè)置為必填,然后使用內(nèi)建的模板驗(yàn)證器,通過正則表達(dá)式來檢查 email 的值:^[a-zA-Z0–9_.+-]+@[a-zA-Z0–9-]+.[a-zA-Z0–9-.]+$.
密碼和確認(rèn)密碼
需求:
- 密碼: 必填,值必須與確認(rèn)密碼的值相同。
- 確認(rèn)密碼: 必填,值必須與密碼的值相同。
<!-- app.component.html --> ... <div> <label>Password</label> <input type="password" name="password" [ngModel]="user.password" required #password="ngModel"> <small [hidden]="password.valid || (password.pristine && !f.submitted)"> Password is required </small> </div> <div> <label>Retype password</label> <input type="password" name="confirmPassword" [ngModel]="user.confirmPassword" required validateEqual="password" #confirmPassword="ngModel"> <small [hidden]="confirmPassword.valid || (confirmPassword.pristine && !f.submitted)"> Password mismatch </small> </div> ...
validateEqual 是我們自定義的驗(yàn)證器。它會將當(dāng)前輸入的值與輸入的密碼值進(jìn)行對比驗(yàn)證。
# 自定義確認(rèn)密碼驗(yàn)證器
我們將制定一個(gè) validate equal 指令。
// equal-validator.directive.ts
import { Directive, forwardRef, Attribute } from '@angular/core';
import { Validator, AbstractControl, NG_VALIDATORS } from '@angular/forms';
@Directive({
selector: '[validateEqual][formControlName],[validateEqual][formControl],[validateEqual][ngModel]',
providers: [
{ provide: NG_VALIDATORS, useExisting: forwardRef(() => EqualValidator), multi: true }
]
})
export class EqualValidator implements Validator {
constructor( @Attribute('validateEqual') public validateEqual: string) {}
validate(c: AbstractControl): { [key: string]: any } {
// self value (e.g. retype password)
let v = c.value;
// control value (e.g. password)
let e = c.root.get(this.validateEqual);
// value not equal
if (e && v !== e.value) return {
validateEqual: false
}
return null;
}
}
代碼很長,讓我們把它拆開一部分一部分地看。
申明指令
// equal-validator.directive.ts
@Directive({
selector: '[validateEqual][formControlName],[validateEqual]
[formControl],[validateEqual][ngModel]',
providers: [
{ provide: NG_VALIDATORS, useExisting: forwardRef(() => EqualValidator), multi: true }
]
})
首先,我們使用 @Directive 注解定義指令。然后我們指定 selector。selector 是必須的。我們會擴(kuò)展內(nèi)建驗(yàn)證器集合 NG_VALIDATORS 來將我們的等值驗(yàn)證器用于 providers.
// equal-validator.directive.ts
export class EqualValidator implements Validator {
constructor( @Attribute('validateEqual') public validateEqual: string) {}
validate(c: AbstractControl): { [key: string]: any } {}
}
我們的指令類必須實(shí)現(xiàn) Validator 接口。Validator 接口需要 avalidate 函數(shù)。在構(gòu)建函數(shù)中,我們通過 @Attribute('validateEqual') 注解注入屬性值,并將其賦值給 validateEqual 變量。在我們的示例中, validateEqual 的值是 "password" 。
實(shí)現(xiàn)驗(yàn)證
// equal-validator.directive.ts
validate(c: AbstractControl): { [key: string]: any } {
// 自己的值 (如 retype password)
let v = c.value;
// 控件的值 (如 password)
let e = c.root.get(this.validateEqual);
// 值不等旱
if (e && v !== e.value) return {
validateEqual: false
}
return null;
}
首先我們從輸入控件讀入值,賦給 v。然后我們在表單中找到 password 控件的值賦值給 e。之后檢查值是否相等,如果不等就返回錯(cuò)。
# 在應(yīng)用模塊中導(dǎo)入自定義驗(yàn)證器
要使用自定義驗(yàn)證器,需要先將其導(dǎo)入到應(yīng)用程序模塊中。
// app.module.ts
...
import { EqualValidator } from './equal-validator.directive'; // 導(dǎo)入驗(yàn)證器
import { AppComponent } from './app.component';
@NgModule({
imports: [ BrowserModule, FormsModule ],
declarations: [ AppComponent, EqualValidator ], // 導(dǎo)入到應(yīng)用模塊
bootstrap: [ AppComponent ],
})
...
好了!假如你在 password 字段中輸入 "123",在 retype password 字段中輸入"xyz",就會顯示一個(gè)密碼不匹配的錯(cuò)誤。
# 看起來挺好,但是……
現(xiàn)在一切都挺好,直到你 在 retype passowrd 中輸入文本之后 又修改了 password 字段的值。
比如,你在 password 字段中輸入 "123",在 retype password 字段中也輸入 "123", 然后將 password 字段的值改為 "1234" 。驗(yàn)證仍然通過。 為什么?
因?yàn)槲覀冎话训戎凋?yàn)證器應(yīng)用到 retype password 字段。只有當(dāng) retype password 的值發(fā)生變化時(shí)才會觸發(fā)驗(yàn)證。
解決辦法
有幾種方法可以解決這個(gè)問題。我們這里只討論其中一種,你自己可以去找到其它辦法。我們會再次使用 validateEqual 驗(yàn)證器并 添加 一個(gè) reverse 屬性。
<!-- app.component.html --> ... <input type="password" class="form-control" name="password" [ngModel]="user.password" required validateEqual="confirmPassword" reverse="true"> <input type="password" class="form-control" name="confirmPassword" [ngModel]="user.confirmPassword" required validateEqual="password"> ...
- reverse 是 false 或者沒有設(shè)置的情況下,我們會像前一節(jié)提到的那樣執(zhí)行等值驗(yàn)證器。
- reverse 是 true 的時(shí)候,我們?nèi)匀粫?zhí)行等值驗(yàn)證器,但它不會為當(dāng)前控件添加錯(cuò)誤消息,而是 為指定 會把的目標(biāo)控件添加錯(cuò)誤消息 。
在我們的例子中,我們設(shè)置 password 驗(yàn)證的 reverse 為 true。只要 password 與 retype password 的 值不等,我們會為確證密碼字段添加一個(gè)錯(cuò)誤消息,而不是重置 password 字段。
完整的自定義驗(yàn)證器代碼如下:
// equal-validator.directive.ts
import { Directive, forwardRef, Attribute } from '@angular/core';
import { Validator, AbstractControl, NG_VALIDATORS } from '@angular/forms';
@Directive({
selector: '[validateEqual][formControlName],[validateEqual][formControl],[validateEqual][ngModel]',
providers: [
{ provide: NG_VALIDATORS, useExisting: forwardRef(() => EqualValidator), multi: true }
]
})
export class EqualValidator implements Validator {
constructor(@Attribute('validateEqual') public validateEqual: string,
@Attribute('reverse') public reverse: string) {
}
private get isReverse() {
if (!this.reverse) return false;
return this.reverse === 'true' ? true: false;
}
validate(c: AbstractControl): { [key: string]: any } {
// self value
let v = c.value;
// control vlaue
let e = c.root.get(this.validateEqual);
// value not equal
if (e && v !== e.value && !this.isReverse) {
return {
validateEqual: false
}
}
// value equal and reverse
if (e && v === e.value && this.isReverse) {
delete e.errors['validateEqual'];
if (!Object.keys(e.errors).length) e.setErrors(null);
}
// value not equal and reverse
if (e && v !== e.value && this.isReverse) {
e.setErrors({ validateEqual: false });
}
return null;
}
}
當(dāng)然,還有其他方法也能解決密碼和確認(rèn)密碼驗(yàn)證問題。有些人建議在組( stack overflow )中添加密碼和確認(rèn)密碼的機(jī)制,然后驗(yàn)證它。
方法沒有絕對的好與壞,適合自己的才是最好的。
以上所述是小編給大家介紹的在 Angular2 中實(shí)現(xiàn)自定義校驗(yàn)指令(確認(rèn)密碼)的方法,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時(shí)回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
Angular懶加載模塊與Combined?Injector原理全面解析
這篇文章主要為大家介紹了Angular懶加載模塊與Combined?Injector原理全面解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10
詳解如何構(gòu)建Angular項(xiàng)目目錄結(jié)構(gòu)
本篇文章主要介紹了詳解如何構(gòu)建Angular項(xiàng)目目錄結(jié)構(gòu),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-07-07
Angular利用內(nèi)容投射向組件輸入ngForOf模板的方法
本篇文章主要介紹了Angular利用內(nèi)容投射向組件輸入ngForOf模板的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-03-03
angular實(shí)現(xiàn)input輸入監(jiān)聽的示例
今天小編就為大家分享一篇angular實(shí)現(xiàn)input輸入監(jiān)聽的示例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08

