Angular 中有两种表单:
Template-Driven Forms - 模板驱动式表单 (类似于 AngularJS 1.x 中的表单 )
Reactive Forms - 响应式表单
我们主要使用响应式表单来进行validator方法验证
首先在 @NgModule 中导入 @angular/forms 库中的 ReactiveFormsModule:
app.module.ts
import { ReactiveFormsModule } from '@angular/forms';
@NgModule({
imports: [
...,
ReactiveFormsModule
],
declarations: [...],
bootstrap: [...]
})
export class AppModule {}
友情提示:若使用响应式表单,则导入 ReactiveFormsModule。若使用模板驱动式表单,则导入 FormsModule 。
然后创建好需要的组件:在控制台输入 ng g component 组件名 可快速创建组件并自动注册
在终端中创建组件$ ng g component Validator
在app.component.html文件中写入所创建的组件
src\app\validator\validator.component.ts
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-validator',
templateUrl: './validator.component.html',
styleUrls: ['./validator.component.css']
})
export class ValidatorComponent implements OnInit {
contactForm: FormGroup = new FormGroup({
name: new FormControl(
"",
[
Validators.required,
Validators.minLength(2)
]
})
onSubmit() {
console.log(this.contactForm.valid);
}
get name() {
return this.contactForm.get("name")
}
constructor() { }
ngOnInit(): void {
}
}
在上述例子中,name 控件设置了两个内置验证器 Validators.required 和 Validators.minLength(2)
在响应式表单中,通常会通过它所属的控件组(FormGroup)的 get 方法来访问表单控件,但有时候为模板定义一些 getter 作为简短形式。
src\app\validator\validator.component.html
name?.errors控件值是否验证错误
控件状态检测,Angular会自动根据控件状态加上相应的class,如果我们需要编辑input标签在不同状态下的样式,只需要在css里写相应的类就可以了。
状态 | true | false |
---|---|---|
控件是否被访问过 | touched | untouched |
控件值是否已经变化 | dirty | pristine |
控件值是否有效 | valid | invalid |
验证器(Validator)函数
验证器函数可以是同步函数,也可以是异步函数。
同步验证器:这些同步函数接受一个控件实例,然后返回一组验证错误或 null。你可以在实例化一个 FormControl 时把它作为构造函数的第二个参数传进去。
异步验证器 :这些异步函数接受一个控件实例并返回一个 Promise 或 Observable,它稍后会发出一组验证错误或 null。在实例化 FormControl 时,可以把它们作为第三个参数传入。
自定义同步验证器
在app文件夹下新建myValidator.ts(文件名任意.ts)文件.
src\app\myValidator.ts
import { AbstractControl, ValidationErrors, ValidatorFn } from "@angular/forms"
export class MyValidators {
static cannotContainSpace(
control: AbstractControl
): ValidationErrors | null {
if (/\s/.test(control.value)) {
return {
cannotContainSpace: true
}
}
return null;
};
static forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } | null => {
const forbidden = nameRe.test(control.value);
return forbidden ? { 'forbiddenName': { value: control.value } } : null;
};
}
}
自定义验证器的类型是TypeScript类,类中包含具体的验证方法,验证方法必须为静态方法。
cannotContainSpace验证方法有一个参数control,类型为AbstractControl,其实就是FormControl类的实例对象的类型。如果验证成功,返回null;如果验证失败,返回对象,对象中的属性即为验证标识,值为true,标识该项验证失败。验证方法的返回值为ValidationErrors | null。
forbiddenNameValidator验证方法实际上是一个工厂,它接受一个用来检测指定名字是否已被禁用的正则表达式,并返回一个验证器函数。工厂函数返回配置好的验证器函数。 该函数接受一个 Angular 控制器对象,并在控制器值有效时返回 null,或无效时返回验证错误对象。 验证错误对象通常有一个名为验证秘钥(forbiddenName)的属性。其值为一个任意词典,你可以用来插入错误信息({name})。
src\app\validator\validator.component.ts
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { MyValidators } from '../myValidator';
@Component({
selector: 'app-validator',
templateUrl: './validator.component.html',
styleUrls: ['./validator.component.css']
})
export class ValidatorComponent implements OnInit {
contactForm: FormGroup = new FormGroup({
name: new FormControl(
"",
[
Validators.required,
Validators.minLength(2),
MyValidators.cannotContainSpace,
MyValidators.forbiddenNameValidator(/bob/i)
]
})
onSubmit() {
console.log(this.contactForm.valid);
}
get name() {
return this.contactForm.get("name")
}
constructor() { }
ngOnInit(): void {
}
}
src\app\validator\validator.component.html
自定义异步验证器
src\app\myValidator.ts
import { AbstractControl, ValidationErrors, ValidatorFn } from "@angular/forms"
export class MyValidators {
static cannotContainSpace(
control: AbstractControl
): ValidationErrors | null {
if (/\s/.test(control.value)) {
return {
cannotContainSpace: true,
}
}
return null;
};
static forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } | null => {
const forbidden = nameRe.test(control.value);
return forbidden ? { 'forbiddenName': { value: control.value } } : null;
};
};
static shouldBeUnique(control: AbstractControl): Promise {
return new Promise(resolve => {
setTimeout(() => {
if (control.value == "admin") {
resolve({ shouldBeUnique: true })
} else {
resolve(null)
}
}, 2000);
})
};
}
该校验器会实现一个shouldBeUnique()方法,返回结构为Promise<> 或者 Observable<> ,control.value 为当前控件的值,如果值为admin,则验证不通过返回错误对象,否则返回null。以上是一个最简单的异步验证器。
异步验证器 validate() 函数必须返回一个 Promise 或可观察对象。验证器函数接受一个control,然后返回一组错误对象(验证不通过)或 null(验证通过),当未返回任何内容时表示未开始校验。
异步校验器要求返回Promise或Observable,同时返回的可观察对象必须是有限的,也就是说,它必须在某个时间点结束(complete)。要把无尽的可观察对象转换成有限的,可以使用 first、last、take 或 takeUntil 等过滤型管道对其进行处理。
验证错误是一个对象,对象结构唯一的要求是key必须为字符串,值可以为any类型,例如你可以返回一个{duplicate: true},表示当前control的duplicate校验未通过。
值得注意的是,出于性能考虑,异步校验器会在所有同步校验器完成之后才会触发,在此之前异步校验器会处于正确状态。
异步验证开始之后,表单控件就会进入 pending 状态,当验证结果返回之后才会变成 valid 或 invalid。可以检查控件的 pending 属性,并用它来给出对验证中的视觉反馈。
src\app\validator\validator.component.ts
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { MyValidators } from '../myValidator';
@Component({
selector: 'app-validator',
templateUrl: './validator.component.html',
styleUrls: ['./validator.component.css']
})
export class ValidatorComponent implements OnInit {
contactForm: FormGroup = new FormGroup({
name: new FormControl(
"",
[
Validators.required,
Validators.minLength(2),
MyValidators.cannotContainSpace,
MyValidators.forbiddenNameValidator(/bob/i)
],
MyValidators.shouldBeUnique)
})
onSubmit() {
console.log(this.contactForm.valid);
}
get name() {
return this.contactForm.get("name")
}
constructor() { }
ngOnInit(): void {
}
}
src\app\validator\validator.component.html
实例:
import { Inject, Injectable } from "@angular/core";
import { AbstractControl, AsyncValidator, ValidationErrors } from "@angular/forms"
import { catchError, map, Observable, of } from "rxjs";
import { NameService } from "./name.service";
@Injectable({
providedIn: 'root'
})
export class nameValidator implements AsyncValidator{
constructor(@Inject(String) private nameService: NameService) { }
validate(control: AbstractControl): Promise | Observable {
//进入管道进行串行 *** 作
return this.nameService.isAlterEgoTaken(control.value).pipe(
//对返回值进行处理,null表示正确,对象表示错误
map(isTaken => (isTaken ? { uniqueAlterEgo: true } : null)),
//处理任何潜在的错误
catchError(() => of(null))
);
}
}
interface NameService {
isAlterEgoTaken: (alterEgo: string) => Observable;
}
在真实的应用中,NameService 会负责向数据库发起一个 HTTP 请求,以检查该数据是否可用。 从该验证器的视角看,此服务的具体实现无关紧要,所以这个例子仅仅针对 NameService 接口来写实现代码。
当验证开始的时候,UniqueAlterEgoValidator 把任务委托给 NameService 的 isAlterEgoTaken() 方法,并传入当前控件的值。这时候,该控件会被标记为 pending 状态,直到 validate() 方法所返回的可观察对象完成(complete)了。
isAlterEgoTaken() 方法会调度一个 HTTP 请求来检查第二人格是否可用,并返回 Observable
与任何验证器一样,如果表单有效,该方法返回 null,如果无效,则返回 ValidationErrors。这个验证器使用 catchError *** 作符来处理任何潜在的错误。在这个例子中,验证器将 isAlterEgoTaken() 错误视为成功的验证,因为未能发出验证请求并不一定意味着这个第二人格无效。你也可以用不同的方式处理这种错误,比如返回 ValidationError 对象。
一段时间过后,这条可观察对象链完成,异步验证也就完成了。pending 标志位也设置为 false,该表单的有效性也已更新。
form.component.ts
contactForm: FormGroup = new FormGroup({
username: new FormControl(
"",
[
Validators.required,
Validators.minLength(2)
],
nameValidator.createValidator(this.nameService)
)
})
constructor( private nameService:NameService) {
}
name.service.ts
import { Injectable } from "@angular/core";
import {HttpClient} from "@angular/common/http";
import {delay,map,filter } from "rxjs/operators";
import { Observable } from "rxjs";
@Injectable()
export class NameService {
constructor(private http: HttpClient) { }
isAlterEgoTaken(alterEgo: string) {
// 返回可观察对象Observable
..............
}
}
自定义验证函数调用系统定义好的验证函数
首先创建validator.ts
src\app\validator.ts
import { AbstractControl, ValidatorFn, Validators } from "@angular/forms";
// 强转类型
export function isValidKey(
key: string | number,
object: object
): key is keyof typeof object {
return key in object;
}
export function validator(data: object): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } | null => {
for (const keyIndex in data) {
if (isValidKey(keyIndex, data)) {
if (Validators.required(control) && keyIndex == 'required' && data[keyIndex]) {
return {
required: data[keyIndex],
errMsg: "输入不能为空"
}
}
else if (Validators.email(control) && keyIndex == 'email'&& data[keyIndex]) {
return {
email: data[keyIndex],
errMsg: "输入必须为Email格式"
}
}
else if (/\s/.test(control.value) && keyIndex == 'cannotContainSpace'&& data[keyIndex]) {
return {
cannotContainSpace: data[keyIndex],
errMsg: "输入不能出现空格"
}
}
else if (/bob/i.test(control.value) && keyIndex == 'forbiddenName'&& data[keyIndex]) {
return {
forbiddenName: data[keyIndex],
errMsg: "输入不能出现bob"
}
}
else if (keyIndex == 'minlength') {
if (Validators.minLength(data[keyIndex])) {
if (control.value.length < data[keyIndex]) {
return {
minlength: {
requiredLength: data[keyIndex]
},
errMsg: "输入最短2个字符"
}
}
}
}
}
}
return null;
}
}
Validators.required(control) && data.required调用内置验证器Validators中的required函数,且当外部约束required为true时进行验证,返回验证和验证结果。在new FormControl( )中设置Validator(参数)验证,在HTML中输出结果{{username?.errors?.['errMsg']}}不用判断错误类型,直接输出错误信息。
src\app\validator\validator.component.ts
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { validator } from '../validator';
@Component({
selector: 'app-validator',
templateUrl: './validator.component.html',
styleUrls: ['./validator.component.css']
})
export class ValidatorComponent implements OnInit {
vliData = {
required: true,
minlength: 2,
forbiddenName: true,
cannotContainSpace: true,
email: false
}
contactForm: FormGroup = new FormGroup({
username: new FormControl(
"",
validator(this.vliData)
)
})
onSubmit() {
console.log(this.contactForm.valid);
console.log(this.username?.valueChanges);
}
get username() {
return this.contactForm.get("username");
}
constructor() {
}
ngOnInit(): void {
}
}
src\app\validator\validator.component.html
在模板驱动表单中验证
创建好需要的组件:在控制台输入 ng g component 组件名 可快速创建组件并自动注册
在终端中创建组件$ ng g component TemplateDrivenForms
在app.component.html文件中写入
src\app\template-driven-forms\template-driven-forms.component.html
src\app\template-driven-forms\template-driven-forms.component.ts
import { Component, OnInit } from '@angular/core';
import { NgForm } from '@angular/forms';
@Component({
selector: 'app-template-driven-forms',
templateUrl: './template-driven-forms.component.html',
styleUrls: ['./template-driven-forms.component.css']
})
export class TemplateDrivenFormsComponent implements OnInit {
constructor() {}
ngOnInit(): void {
}
onSubmit(form:NgForm){
console.log(form.valid);
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)