Angular5+ 自定义表单验证器
Custom Validators
标签(空格分隔): Angular
首先阐述一下遇到的问题:
怎样实现“再次输入密码”的验证(两个controller值相等)(equalTo) 怎样反向监听(先输入“再次输入密码”,后输入设置密码)解决思路:
第一个问题,可以通过 [AbstractControl].root.get([targetName]) 来取得指定的controller,然后比较他们的值。 第二个,可以通过 [target].setErrors([errors]) 来实现。 这是一个我的自定义表单验证:import {AbstractControl, FormGroup, ValidatorFn} from \'@angular/forms\'; import {G} from \'services/data-store.service\'; export class MyValidators { private static isEmptyInputValue(value) { // we don\'t check for string here so it also works with arrays return value == null || value.length === 0; } private static isEmptyObject(obj) { if (typeof obj === \'object\' && typeof obj.length !== \'number\') { return Object.keys(obj).length === 0; } return null; } /** * 等于指定controller的值 * @param targetName 目标的formControlName * @returns {(ctrl: FormControl) => {equalTo: {valid: boolean}}} */ static equalTo(targetName: string): ValidatorFn { return (control: AbstractControl): {[key: string]: any} | null => { const target = control.root.get(targetName); if (target === null) { return null; } if (this.isEmptyInputValue(control.value)) { return null; } return target.value === control.value ? null : {\'equalto\': { valid: false }}; }; } /** * 反向输入监听指定controller是否与当前值相等 * @param targetName */ static equalFor(targetName: string): ValidatorFn { return (control: AbstractControl): {[key: string]: any} | null => { const target = control.root.get(targetName); if (target === null) { return null; } if (this.isEmptyInputValue(control.value)) { return null; } if (target.value === control.value) { const errors = target.errors; delete errors[\'equalto\']; if (this.isEmptyObject(errors)) { target.setErrors(null); } else { target.setErrors(errors); } return null; } target.setErrors({ \'equalto\': { valid: false } }); }; } ... }
(注:)其中 G.REGEX 等的是全局变量。
然后 FormBuilder 来实现:import { Component, OnInit } from \'@angular/core\'; import {EventsService} from \'services/events.service\'; import {FormBuilder, FormGroup, Validators} from \'@angular/forms\'; import {G} from \'services/data-store.service\'; import {fade} from \'animations/fade.animation\'; import {MyValidators} from \'directives/my-validators.directive\'; @Component({ selector: \'app-sign-up\', templateUrl: \'./sign-up.component.html\', styleUrls: [\'./sign-up.component.scss\'], animations: [fade] }) export class SignUpComponent implements OnInit { signForm: FormGroup; // 表单组FormGroup submitting: boolean; // 是否可以提交 validations = G.VALIDATIONS; constructor(private eventsService: EventsService, private formBuilder: FormBuilder) { this.submitting = false; // this.init(); } ngOnInit() { // 设置父组件标题 this.eventsService.publish(\'setSign\', { title: \'注册\', subTitle: { name: \'立即登录\', uri: \'/account/sign-in\' } }); } // 立即注册 onSubmit() { console.log(this.signForm.getRawValue()); } // 表单初始化 private init() { this.signForm = this.formBuilder.group({ username: [\'\', Validators.compose([Validators.required, Validators.maxLength(this.validations.USR_MAX)])], password: [\'\', Validators.compose([ Validators.required, Validators.minLength(this.validations.PASS_MIN), Validators.maxLength(this.validations.PASS_MAX), MyValidators.equalFor(\'passwordConfirm\') ])], passwordConfirm: [\'\', Validators.compose([ Validators.required, Validators.minLength(this.validations.PASS_MIN), Validators.maxLength(this.validations.PASS_MAX), MyValidators.equalTo(\'password\') ])] }); } }
(注:)其中 fade 动画效果。
然后在html模板中,显示表单验证提示信息:<form [formGroup]="signForm" (ngSubmit)="onSubmit()" class="sign-form" @fade> <!-- 账号 --> <div class="input-group username"> <span class="addon prev"><i class="civ civ-i-usr"></i></span> <input type="text" name="username" class="form-control form-control-left default" placeholder="请输入账号" formControlName="username" autocomplete="off"> <ul class="errors" *ngIf="signForm.get(\'username\').invalid && (signForm.get(\'username\').dirty || signForm.get(\'username\').touched)"> <li *ngIf="signForm.get(\'username\').hasError(\'required\')" class="error"> 请输入您的账号! </li> <li *ngIf="signForm.get(\'username\').hasError(\'maxlength\')" class="error"> 账号不超过{{ validations.USR_MAX }}位! </li> </ul> </div> <!-- /.账号 --> <!-- 密码 --> <div class="input-group password"> <span class="addon prev"><i class="civ civ-i-lock"></i></span> <input type="password" name="password" class="form-control form-control-left default" placeholder="请输入密码" formControlName="password"> <ul class="errors" *ngIf="signForm.get(\'password\').invalid && (signForm.get(\'password\').dirty || signForm.get(\'password\').touched)"> <li *ngIf="signForm.get(\'password\').hasError(\'required\')" class="error"> 请输入您的密码! </li> <li *ngIf="signForm.get(\'password\').hasError(\'minlength\')" class="error"> 请输入至少{{ validations.PASS_MIN }}位数的密码! </li> <li *ngIf="signForm.get(\'password\').hasError(\'maxlength\')" class="error"> 密码不超过{{ validations.PASS_MAX }}位! </li> </ul> </div> <!-- /.密码 --> <!-- 重复密码 --> <div class="input-group password-confirm"> <span class="addon prev"><i class="civ civ-i-lock"></i></span> <input type="password" name="passwordConfirm" class="form-control form-control-left default" placeholder="请再次输入密码" formControlName="passwordConfirm"> <ul class="errors" *ngIf="signForm.get(\'passwordConfirm\').invalid && (signForm.get(\'passwordConfirm\').dirty || signForm.get(\'passwordConfirm\').touched)"> <li *ngIf="signForm.get(\'passwordConfirm\').hasError(\'required\')" class="error"> 请再次输入密码! </li> <li *ngIf="signForm.get(\'passwordConfirm\').hasError(\'minlength\')" class="error"> 请输入至少{{ validations.PASS_MIN }}位数的密码! </li> <li *ngIf="signForm.get(\'passwordConfirm\').hasError(\'maxlength\')" class="error"> 密码不超过{{ validations.PASS_MAX }}位! </li> <li *ngIf="!signForm.get(\'passwordConfirm\').hasError(\'maxlength\') && !signForm.get(\'passwordConfirm\').hasError(\'minlength\') && signForm.get(\'passwordConfirm\').hasError(\'equalto\')" class="error"> 两次密码输入不一致! </li> </ul> </div> <!-- /.重复密码 --> <!-- 提交按钮 --> <button type="submit" class="btn btn-primary btn-block submit" [disabled]="submitting || signForm.invalid">立即注册</button> <!-- /.提交按钮 --> </form>
最后,我们可以看到,实现了想要的效果:
(附:)完整的自定义表单验证器:
import {AbstractControl, FormGroup, ValidatorFn} from \'@angular/forms\'; import {G} from \'services/data-store.service\'; export class MyValidators { private static isEmptyInputValue(value) { // we don\'t check for string here so it also works with arrays return value == null || value.length === 0; } private static isEmptyObject(obj) { if (typeof obj === \'object\' && typeof obj.length !== \'number\') { return Object.keys(obj).length === 0; } return null; } /** * 等于指定controller的值 * @param targetName 目标的formControlName * @returns {(ctrl: FormControl) => {equalTo: {valid: boolean}}} */ static equalTo(targetName: string): ValidatorFn { return (control: AbstractControl): {[key: string]: any} | null => { const target = control.root.get(targetName); if (target === null) { return null; } if (this.isEmptyInputValue(control.value)) { return null; } return target.value === control.value ? null : {\'equalto\': { valid: false }}; }; } /** * 反向输入监听指定controller是否与当前值相等 * @param targetName */ static equalFor(targetName: string): ValidatorFn { return (control: AbstractControl): {[key: string]: any} | null => { const target = control.root.get(targetName); if (target === null) { return null; } if (this.isEmptyInputValue(control.value)) { return null; } if (target.value === control.value) { const errors = target.errors; delete errors[\'equalto\']; if (this.isEmptyObject(errors)) { target.setErrors(null); } else { target.setErrors(errors); } return null; } target.setErrors({ \'equalto\': { valid: false } }); }; } /** * 验证手机号 * @returns {(ctrl: FormControl) => {mobile: {valid: boolean}}} */ static get mobile() { return (control: AbstractControl) => { if (this.isEmptyInputValue(control.value)) { return null; } const valid = G.REGEX.MOBILE.test(control.value); return valid ? null : { \'mobile\': { valid: false } }; }; } /** * 验证身份证 * @returns {(ctrl: FormControl) => {idCard: {valid: boolean}}} */ static get idCard() { return (control: AbstractControl) => { if (this.isEmptyInputValue(control.value)) { return null; } const valid = G.REGEX.ID_CARD.test(control.value); return valid ? null : { \'idcard\': { valid: false } }; }; } /** * 验证汉字 * @returns {(ctrl: FormControl) => {cn: {valid: boolean}}} */ static get cn() { return (control: AbstractControl) => { if (this.isEmptyInputValue(control.value)) { return null; } const valid = G.REGEX.CN.test(control.value); return valid ? null : { \'cn\': { valid: false } }; }; } /** * 指定个数数字 * @param {number} length * @returns {(ctrl: FormControl) => (null | {number: {valid: boolean}})} */ static number(length: number = 6) { return (control: AbstractControl) => { if (this.isEmptyInputValue(control.value)) { return null; } const valid = new RegExp(`^\\d{${length}}$`).test(control.value); return valid ? null : { \'number\': { valid: false } }; }; } /** * 强密码(必须包含数字字母) * @returns {(ctrl: FormControl) => (null | {number: {valid: boolean}})} */ static get strictPass() { return (control: AbstractControl) => { if (this.isEmptyInputValue(control.value)) { return null; } const valid = G.REGEX.STRICT_PASS.test(control.value); return valid ? null : { \'strictpass\': { valid: false } }; }; } }
查看更多关于Angular5+ 自定义表单验证器的详细内容...
声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://haodehen.cn/did223034