Angular 4中的表单简介:编写自定义表单验证器

这是在Angular中创建表单系列的第三部分。 在前两个教程中,我们使用Angular的模板驱动和模型驱动方法来创建表单。 但是,在详细介绍这两种方法时,我们没有涉及到某些内容-自定义验证程序功能。 本教程将介绍编写符合您要求的自定义验证程序所需的所有知识。

先决条件

您无需遵循本系列的第一部分或第二部分就可以使第三部分变得有意义。 但是,如果您对Angular中的表单完全陌生,则应该转到本系列第一个教程并从那里开始。

否则,请从我们的GitHub存储库中获取此代码的副本,并将其作为起点。

内置验证器

Angular没有夸大的内置验证器库。 从Angular 4开始,我们在Angular中使用以下流行的验证器:

  • 需要
  • 最小长度
  • 最长长度
  • 模式

实际上还有更多,您可以在Angular文档中查看完整列表。

我们可以通过两种方式使用上述内置验证器:

1.作为模板驱动形式的指令。

<input name="fullName" ngModel required>

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是创建FormGroupFormControl实例的语法糖。 FormControl跟踪单个表单元素的值和验证状态。 另一方面, FormGroup FormControl实例,它跟踪整个组的值和有效性。

这是我们一直遵循的结构:

FormGroup -> 'signupForm'
    FormControl -> 'email'
    FormGroup -> 'password'
        FormControl -> 'pwd'
        FormControl -> 'confirmPwd'
    FormControl -> 'gender'

根据要求,我们可以将验证器附加到FormControlFormGroup 。 电子邮件黑名单验证器将要求将其附加到电子邮件的FormControl实例。

但是,对于必须比较和验证多个控制字段的更复杂的验证,最好将验证逻辑添加到父FormGroup 。 如您所见, password具有自己的FormGroup ,这使我们很容易编写验证器来检查pwdconfirmPwd的相等性。

对于模板驱动的表单,所有逻辑都包含在HTML模板中,下面是一个示例:

app / signup-form / signup-form.component.html
<form novalidate 
    	(ngSubmit)="onFormSubmit(signupForm)" 
		#signupForm="ngForm">
        
	<!-- Email input block -->
	<input type="text" 
	    [ngModel] = "user.email" name="email"
        pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,3}$"
        required>

	<!-- Password block -->
	<div ngModelGroup="password">
	    <input type="password"
		        ngModel name="pwd"
	            minlength ="8" required
	           >
	    <input type="password" class="form-control"
		        ngModel name="confirmPwd"
	           >
	    
	</div>
	   
...

	<!-- Select Gender block -->
    <select id="select" class="form-control"
          [ngModel] = "user.gender" name = "gender"
          required>
       
        </select>
    </form>

ngModel创建FormControl的实例,并将其绑定到表单控件元素。 同样, ngModelGroup创建FormGroup实例并将其绑定到DOM元素。 它们共享上面讨论的相同模型域结构。

还有趣的是, FormControlFormGroupFormArray扩展了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 error block -->
       <div *ngIf="(password.invalid && password.touched)">
     
      </div>

我们使用password.touched来确保即使在按下某个键之前也不会出现错误。

接下来,我将使用ngIf =“ expression; then a else b”语法来显示正确的错误。

app / signup-form / signup-form.component.html
<ng-container *ngIf="password.errors?.mismatch;  
                then first else second"> </ng-container>
    
    <ng-template #first> 
        Password do not match </ng-template>
    
    <ng-template #second>  
        Password needs to be more than 8 characters
    </ng-template>

在那里,验证器的工作模型将检查密码是否相等。

模型驱动形式的自定义验证器演示

我已经将自定义验证器演示的代码添加到GitHub存储库中 。 您可以下载或克隆该项目以进行尝试。

模板驱动表单的自定义验证器指令

我们将使用与之前为模型驱动表单创建的验证函数相同的函数。 但是,我们无法以模板驱动的形式直接访问FormControl / FormGroup实例。 这是使验证器正常工作所需要做的事情:

  1. 创建一个PasswordMatchDirective ,用作passwordMatch验证程序函数的包装。 我们将使用NG_VALIDATORS提供程序将指令注册为验证器。 稍后再详细介绍。
  2. 将指令附加到模板表单控件。

让我们先编写指令。 这是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 {
}
  1. 现在,该指令已附加到所有具有ngModelGrouppasswordMatch属性的输入控件。
  2. 我们使用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 error block -->
<div *ngIf="(userPassword.invalid && userPassword.touched)">
			 	
	<ng-container *ngIf="userPassword.errors?.mismatch;  
        then first else second">
    </ng-container>
    <ng-template #first> Password do not match </ng-template>
  
    <ng-template #second>  
        Password needs to be more than 8 characters
    </ng-template>
</div>

结论

在本教程中,我们学习了如何为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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值