Angular 4.x中表单Reactive Forms详解

Angular 4.x中表单Reactive Forms详解

这篇文章主要介绍了Angular 4.x中表单Reactive Forms的相关资料,文中通过示例代码介绍的非常详细,相信对大家具有一定的参考价值,需要的朋友们下面来一起看看吧。

Angular 4.x 中有两种表单:

  • Template-Driven Forms - 模板驱动式表单 (类似于 Angular 1.x 中的表单 )
  • Reactive Forms (Model-Driven Forms) - 响应式表单

Template-Driven Forms (模板驱动表单) ,我们之前的文章已经介绍过了,了解详细信息,请查看 - Angular 4.x Template-Driven Forms

Contents

  • ngModule and reactive forms
  • FormControl and FormGroup
  • Implementing our FormGroup model
  • Binding our FormGroup model
  • Reactive submit
  • Reactive error validation
  • Simplifying with FormBuilder

Form base and interface

Form base

 

接下来我们要实现的功能如下:

  • 绑定 name、email、confirm 输入框的值
  • 为所有输入框添加表单验证功能
  • 显示验证异常信息
  • 表单验证失败时,不允许进行表单提交
  • 表单提交功能

User interface

 // signup.interface.ts export interface User { name: string; account: { email: string; confirm: string; } }

ngModule and reactive forms

在我们继续深入介绍 reactive forms 表单前,我们必须在 @NgModule 中导入 @angular/forms 库中的 ReactiveFormsModule:

 import { ReactiveFormsModule } from '@angular/forms'; @NgModule({ imports: [ ..., ReactiveFormsModule ], declarations: [...], bootstrap: [...] }) export class AppModule {}

友情提示:若使用 reactive forms,则导入 ReactiveFormsModule;若使用 template-driven 表单,则导入 FormsModule。

Reactive approach

我们将基于上面的定义的基础表单,创建 SignupFormComponent :

signup-form.component.ts

 import { Component } from '@angular/core'; @Component({ selector: 'signup-form', template: ` 
...
` }) export class SignupFormComponent { constructor() {} }

这是一个基础的组件,在我们实现上述功能前,我们需要先介绍 FormControl、FormGroup、FormBuilder 的概念和使用。

FormControl and FormGroup

我们先来介绍一下 FormControl 和 FormGroup 的概念:

1、FormControl - 它是一个为单个表单控件提供支持的类,可用于跟踪控件的值和验证状态,此外还提供了一系列公共API。
使用示例:

 ngOnInit() { this.myControl = new FormControl('Semlinker'); }

2、FormGroup - 包含是一组 FormControl 实例,可用于跟踪 FormControl 组的值和验证状态,此外也提供了一系列公共API。

使用示例:

 ngOnInit() { this.myGroup = new FormGroup({ name: new FormControl('Semlinker'), location: new FormControl('China, CN') }); }

现在我们已经创建了 FormControl 和 FormGroup 实例,接下来我们来看一下如何使用:

 
Name: Location:

注意事项:Template-Driven Forms 中介绍的 ngModel 和 name="" 属性,已经被移除了。这是一件好事,让我们的模板更简洁。

上面示例中,我们必须使用 [formGroup] 绑定我们创建的 myGroup 对象,除此之外还要使用 formControlName 指令,绑定我们创建的 FormControl 控件。

此时的表单结构如下:

 FormGroup -> 'myGroup' FormControl -> 'name' FormControl -> 'location'

Implementing our FormGroup model

signup.interface.ts

 export interface User { name: string; account: { email: string; confirm: string; } }

与之对应的表单结构如下:

 FormGroup -> 'user' FormControl -> 'name' FormGroup -> 'account' FormControl -> 'email' FormControl -> 'confirm'

是的,我们可以创建嵌套的 FormGroup 集合!让我们更新一下组件 (不包含初始数据):

 import { Component, OnInit } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; @Component({...}) export class SignupFormComponent implements OnInit { user: FormGroup; ngOnInit() { this.user = new FormGroup({ name: new FormControl(''), account: new FormGroup({ email: new FormControl(''), confirm: new FormControl('') }) }); } }

如果我们想要设置初始数据,我们可以按照上述示例进行设置。通常情况下,我们通过服务端提供的 API 接口来获取表单的初始信息。

Binding our FormGroup model

现在我们已经实例化了 FormGroup 模型,是时候绑定到对应的 DOM 元素上了。具体示例如下:

 

现在 FormGroup 与 FormControl 对象与 DOM 结构的关联信息如下:

 // JavaScript APIs FormGroup -> 'user' FormControl -> 'name' FormGroup -> 'account' FormControl -> 'email' FormControl -> 'confirm' // DOM bindings formGroup -> 'user' formControlName -> 'name' formGroupName -> 'account' formControlName -> 'email' formControlName -> 'confirm'

当使用模板驱动的表单时,为了获取 f.value 表单的值,我们需要先执行 #f="ngForm" 的操作。而对于使用响应式的表单,我们可以通过以下方式,方便的获取表单的值:

 {{ user.value | json }} // { name: '', account: { email: '', confirm: '' }}

Reactive submit

跟模板驱动的表单一样,我们可以通过 ngSubmit 输出属性,处理表单的提交逻辑:

 
...

需要注意的是:我们使用 user 对象作为 onSubmit() 方法的参数,这使得我们可以获取表单对象的相关信息,具体处理逻辑如下:

 export class SignupFormComponent { user: FormGroup; onSubmit({ value, valid }: { value: User, valid: boolean }) { console.log(value, valid); } }

上面代码中,我们使用 Object destructuring (对象解构) 的方式,从user 对象中获取 value 和 valid 属性的值。其中 value 的值,就是 user.value 的值。在实际应用中,我们是不需要传递 user 参数的:

 export class SignupFormComponent { user: FormGroup; onSubmit() { console.log(this.user.value, this.user.valid); } }

表单的数据绑定方式和提交逻辑已经介绍完了,是该介绍表单实际应用中,一个重要的环节 ― 表单验证。

Reactive error validation

接下来我们来为表单添加验证规则,首先我们需要从 @angular/forms 中导入 Validators。具体使用示例如下:

 ngOnInit() { this.user = new FormGroup({ name: new FormControl('', [Validators.required, Validators.minLength(2)]), account: new FormGroup({ email: new FormControl('', Validators.required), confirm: new FormControl('', Validators.required) }) }); }

通过以上示例,我们可以看出,如果表单控制包含多种验证规则,可以使用数组声明多种验证规则。若只包含一种验证规则,直接声明就好。通过这种方式,我们就不需要在模板的输入控件中添加 required 属性。接下来我们来添加表单验证失败时,不允许进行表单提交功能:

 
...

那么问题来了,我们要如何获取表单控件的验证信息?我们可以使用模板驱动表单中介绍的方式,具体如下:

 
{{ user.controls.name?.errors | json }}

友情提示: ?.prop 称为安全导航操作符,用于告诉 Angular prop 的值可能不存在。

此外我们也可以使用 FormGroup 对象提供的 API,来获取表单控件验证的错误信息:

 
{{ user.get('name').errors | json }}

现在我们来看一下完整的代码:

 import { Component, OnInit } from '@angular/core'; import { FormControl, FormGroup, Validators } from '@angular/forms'; import { User } from './signup.interface'; @Component({ selector: 'signup-form', template: ` 
Name is required
Minimum of 2 characters
Email is required
Confirming email is required
` }) export class SignupFormComponent implements OnInit { user: FormGroup; constructor() {} ngOnInit() { this.user = new FormGroup({ name: new FormControl('', [Validators.required, Validators.minLength(2)]), account: new FormGroup({ email: new FormControl('', Validators.required), confirm: new FormControl('', Validators.required) }) }); } onSubmit({ value, valid }: { value: User, valid: boolean }) { console.log(value, valid); } }

功能是实现了,但创建 FormGroup 对象的方式有点繁琐,Angular 团队也意识到这点,因此为我们提供 FormBuilder ,来简化上面的操作。

Simplifying with FormBuilder

首先我们需要从 @angular/forms 中导入 FormBuilder:

 import { FormBuilder, FormGroup, Validators } from '@angular/forms'; export class SignupFormComponent implements OnInit { user: FormGroup; constructor(private fb: FormBuilder) {} ... }

然后我们使用 FormBuilder 对象提供的 group() 方法,来创建 FormGroup 和 FormControl 对象:

调整前的代码 (未使用FormBuilder):

 ngOnInit() { this.user = new FormGroup({ name: new FormControl('', [Validators.required, Validators.minLength(2)]), account: new FormGroup({ email: new FormControl('', Validators.required), confirm: new FormControl('', Validators.required) }) }); }

调整后的代码 (使用FormBuilder):

 ngOnInit() { this.user = this.fb.group({ name: ['', [Validators.required, Validators.minLength(2)]], account: this.fb.group({ email: ['', Validators.required], confirm: ['', Validators.required] }) }); }

对比一下调整前和调整后的代码,是不是感觉一下子方便了许多。此时更新完后完整的代码如下:

 @Component({...}) export class SignupFormComponent implements OnInit { user: FormGroup; constructor(private fb: FormBuilder) {} ngOnInit() { this.user = this.fb.group({ name: ['', [Validators.required, Validators.minLength(2)]], account: this.fb.group({ email: ['', Validators.required], confirm: ['', Validators.required] }) }); } onSubmit({ value, valid }: { value: User, valid: boolean }) { console.log(value, valid); } }

我有话说

Template-Driven Forms vs Reactive Forms

Template-Driven Forms (模板驱动表单) 的特点

  • 使用方便
  • 适用于简单的场景
  • 通过 [(ngModel)] 实现数据双向绑定
  • 最小化组件类的代码
  • 不易于单元测试

Reactive Forms (响应式表单) 的特点

  • 比较灵活
  • 适用于复杂的场景
  • 简化了HTML模板的代码,把验证逻辑抽离到组件类中
  • 方便的跟踪表单控件值的变化
  • 易于单元测试

总结

以上就是Angular 4.x中表单Reactive Forms详解的详细内容,更多请关注易知道|edz.cc其它相关文章!

推荐阅读