这是在Angular中创建表单系列的第三部分。 在前两个教程中,我们使用Angular的模板驱动和模型驱动方法来创建表单。 但是,在详细介绍这两种方法时,我们没有涉及到某些内容-自定义验证程序功能。 本教程将介绍编写符合您要求的自定义验证程序所需的所有知识。
先决条件
您无需遵循本系列的第一部分或第二部分就可以使第三部分变得有意义。 但是,如果您对Angular中的表单完全陌生,则应该转到本系列的第一个教程并从那里开始。
否则,请从我们的GitHub存储库中获取此代码的副本,并将其作为起点。
内置验证器
Angular没有夸大的内置验证器库。 从Angular 4开始,我们在Angular中使用以下流行的验证器:
- 需要
- 最小长度
- 最长长度
- 模式
实际上还有更多,您可以在Angular文档中查看完整列表。
我们可以通过两种方式使用上述内置验证器:
1.作为模板驱动形式的指令。
2.作为模型驱动形式的FormControl
构造函数中的验证器。
name = new FormControl('', Validators.required)
如果上述语法没有意义,请按照我以前的有关使用模板驱动方法或模型驱动方法构建注册表单的教程进行操作,然后回退!
内置的表单验证器几乎无法涵盖实际应用程序中可能需要的所有验证用例。 例如,注册表单可能需要检查密码的值并确认密码控制字段是否相等,如果不匹配,则显示错误消息。 将来自特定域的电子邮件列入黑名单的验证器是另一个常见示例。
这是事实:模板驱动的表单只是下面的模型驱动的表单。 在模板驱动的形式中,我们让模板负责为我们创建模型。 现在显而易见的问题是,如何将验证器附加到表单?
验证器只是功能。 在模型驱动的表单中,将验证符附加到FormControl很简单。 但是,以模板驱动的形式,还有更多的工作要做。 除了验证器功能之外,您还需要为验证器编写指令,并在模板中创建该指令的实例。
深入细节
尽管已经讨论过了,但我们将快速回顾一下注册表单的代码。 首先,这是反应性方法。
app / signup-form / signup-form.component.ts
// Use the formbuilder to build the Form model
this.signupForm = this.fb.group({
email: ['',[Validators.required,
Validators.pattern('[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,3}$')]],
password: this.fb.group({
pwd: ['', [Validators.required,
Validators.minLength(8)]],
confirmPwd: ['', [Validators.required,
Validators.minLength(8)
]]
}, { validator: PasswordMatch }),
gender: ['', Validators.required],
})
FormBuilder
是创建FormGroup
和FormControl
实例的语法糖。 FormControl
跟踪单个表单元素的值和验证状态。 另一方面, FormGroup
FormControl
实例,它跟踪整个组的值和有效性。
这是我们一直遵循的结构:
FormGroup -> 'signupForm'
FormControl -> 'email'
FormGroup -> 'password'
FormControl -> 'pwd'
FormControl -> 'confirmPwd'
FormControl -> 'gender'
根据要求,我们可以将验证器附加到FormControl
或FormGroup
。 电子邮件黑名单验证器将要求将其附加到电子邮件的FormControl
实例。
但是,对于必须比较和验证多个控制字段的更复杂的验证,最好将验证逻辑添加到父FormGroup
。 如您所见, password
具有自己的FormGroup
,这使我们很容易编写验证器来检查pwd
和confirmPwd
的相等性。
对于模板驱动的表单,所有逻辑都包含在HTML模板中,下面是一个示例:
app / signup-form / signup-form.component.html
ngModel
创建FormControl
的实例,并将其绑定到表单控件元素。 同样, ngModelGroup
创建FormGroup
实例并将其绑定到DOM元素。 它们共享上面讨论的相同模型域结构。
还有趣的是, FormControl
, FormGroup
和FormArray
扩展了AbstractControl
类。 这意味着AbstractControl
类负责跟踪表单对象的值,对其进行验证,并为其他方法(例如原始方法,脏方法和触摸方法)提供动力。
现在我们已经熟悉了两种表单技术,让我们编写第一个自定义验证器。
用于模型驱动表单的自定义验证器功能
验证器是将FormControl
/ FormGroup
实例作为输入并返回null
或错误对象的函数。 验证成功时返回null
;否则,抛出错误对象。 这是验证功能的一个非常基本的版本。
app / password-match.ts
import { FormGroup } from '@angular/forms';
export function passwordMatch(
control: FormGroup):{[key: string]: boolean} {
}
我已经声明了一个函数,该函数接受FormGroup
一个实例作为输入。 它返回一个带有字符串类型的键和一个真/假值的对象。 这样我们就可以返回以下形式的错误对象:
{
mismatch: true
}
接下来,我们需要获取pwd
的值和confirmPwd
FormControl实例。 我将使用control.get()
来获取它们的值。
export function passwordMatch
(control: FormGroup):{[key: string]: boolean} {
//Grab pwd and confirmPwd using control.get
const pwd = control.get('pwd');
const confirmPwd = control.get('confirmPwd');
}
现在我们需要进行比较,然后返回null或错误对象。
app / password-match.ts
import { AbstractControl } from '@angular/forms';
export function passwordMatch
(control: AbstractControl):{[key: string]: boolean} {
//Grab pwd and confirmPwd using control.get
const pwd = control.get('pwd');
const confirmPwd = control.get('confirmPwd');
// If FormControl objects don't exist, return null
if (!pwd || !confirmPwd) return null;
//If they are indeed equal, return null
if (pwd.value === confirmPwd.value) {
return null;
}
//Else return false
return {
mismatch: true };
}
为什么我用AbstractControl
替换FormGroup
? 如您所知, AbstractControl
是所有Form *类的母亲,它为您提供了对表单控件对象的更多控制。 它具有使我们的验证代码更加一致的附加好处。
在SignupForm
组件中导入passwordMatch
函数,并将其声明为密码FormGroup
实例的验证器。
app / password-match.ts
import { passwordMatch } from './../password-match';
.
.
.
export class SignupFormComponent implements OnInit {
ngOnInit() {
// Use the formbuilder to build the Form model
this.signupForm = this.fb.group({
...
password: this.fb.group({
pwd: ['', [Validators.required,
Validators.minLength(8)]],
confirmPwd: ['', [Validators.required,
Validators.minLength(8)
]]
}, { validator: passwordMatch }),
...
})
}
}
显示错误
如果您做的一切正确, password.errors?.mismatch
只要两个字段的值都不匹配, password.errors?.mismatch
就会为真。
{{ password.errors?.mismatch } json }}
尽管还有其他显示错误的方法,但是我将使用ngIf
指令来确定是否显示错误消息。
首先,我将使用ngIf
来查看密码是否无效。
我们使用password.touched
来确保即使在按下某个键之前也不会出现错误。
接下来,我将使用ngIf =“ expression; then a else b”语法来显示正确的错误。
app / signup-form / signup-form.component.html
Password do not match
Password needs to be more than 8 characters
在那里,验证器的工作模型将检查密码是否相等。
模型驱动形式的自定义验证器演示
我已经将自定义验证器演示的代码添加到GitHub存储库中 。 您可以下载或克隆该项目以进行尝试。
模板驱动表单的自定义验证器指令
我们将使用与之前为模型驱动表单创建的验证函数相同的函数。 但是,我们无法以模板驱动的形式直接访问FormControl
/ FormGroup
实例。 这是使验证器正常工作所需要做的事情:
- 创建一个
PasswordMatchDirective
,用作passwordMatch
验证程序函数的包装。 我们将使用NG_VALIDATORS
提供程序将指令注册为验证器。 稍后再详细介绍。 - 将指令附加到模板表单控件。
让我们先编写指令。 这是Angular中的指令:
app / password-match.ts
import { AbstractControl } from '@angular/forms';
export function passwordMatch
(control: AbstractControl):{[key: string]: boolean} {
//Grab pwd and confirmPwd using control.get
const pwd = control.get('pwd');
const confirmPwd = control.get('confirmPwd');
// If FormControl objects don't exist, return null
if (!pwd || !confirmPwd) return null;
//If they are indeed equal, return null
if (pwd.value === confirmPwd.value) {
return null;
}
//Else return false
return {
mismatch: true };
}
//PasswordMatchDirective
@Directive({
selector: '',
providers: [
]
})
export class PasswordMatchDirective {
}
@Directive
装饰器用于将类标记为Angular指令。 它接受一个对象作为参数,用于指定指令配置元数据,例如应该附加指令的选择器,要注入的Provider列表等。让我们填写指令元数据:
app / password-match.ts
@Directive({
selector: '[passwordMatch][ngModelGroup]', //1
providers: [ //2
{
provide: NG_VALIDATORS,
useValue: passwordMatch,
multi: true
}
]
})
export class PasswordMatchDirective {
}
- 现在,该指令已附加到所有具有
ngModelGroup
和passwordMatch
属性的输入控件。 - 我们使用
NG_VALIDATORS
提供程序扩展了内置验证器。 如前所述,NG_VALIDATORS
是具有可扩展验证器集合的提供程序。 我们先前创建的passwordMatch
函数被声明为依赖项。multi: true
将此提供程序设置为多重提供程序。 这意味着我们将添加到NG_VALIDATORS
提供的验证器的现有集合中。
现在,将该指令添加到ngModule
的声明数组中。
app / app.module.ts
...
import {PasswordMatchDirective} from './password-match';
@NgModule({
declarations: [
AppComponent,
SignupFormComponent,
PasswordMatchDirective
],
imports: [
BrowserModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
显示错误信息
为了显示验证错误消息,我将使用为模型驱动表单创建的模板。
Password do not match
Password needs to be more than 8 characters
结论
在本教程中,我们学习了如何为Angular中的表单创建自定义Angular验证器。
验证器是返回null或错误对象的函数。 在模型驱动的表单中,我们必须将验证器附加到FormControl / FormGroup实例,仅此而已。 该过程以模板驱动的形式更为复杂,因为我们需要在验证函数的顶部创建一个指令。
如果您有兴趣继续学习有关JavaScript的更多信息,请记住查看Envato Market中的功能 。
希望您喜欢Angular中的Forms系列。 我很想听听您的想法。 通过评论分享。
翻译自: https://code.tutsplus.com/tutorials/introduction-to-forms-in-angular-4-writing-custom-form-validators--cms-29856