Angular 4.x中表单Reactive Forms详解

网友投稿 270 2023-05-20


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

Full name

type="text"

name="name"

placeholder="Your full name">

Email address

type="email"

name="email"

placeholder="Your email address">

Confirm address

type="email"

name="confirm"

placeholder="Confirm your email address">

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

绑定 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 元素上了。具体示例如下:

Full name

type="text"

placeholder="Your full name"

formControlName="name">

Email address

type="email"

placeholder="Your email address"

formControlName="email">

Confirm address

type="email"

placeholder="Confirm your email address"

formControlName="confirm">

现在 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: `

Full name

user.get('name').touched">

Name is required

user.get('name').touched">

Minimum of 2 characters

Email address

class="error"

*ngIf="user.get('account').get('email').hasError('required') &&

user.get('account').get('email').touched">

Email is required

Confirm address

formControlName="confirm">

class="error"

*ngIf="user.get('account').get('confirm').hasError('required') &&

user.get('account').get('confirm').touched">

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 implemUskKMhXHYents OnInit {

user: FormGroup;

constructor(private fb: FormBuilder) {}

ngOnInit() {

this.user = this.fb.group({

name: ['', [Validators.required, Validators.minLength(UskKMhXHY2)]],

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模板的代码,把验证逻辑抽离到组件类中

方便的跟踪表单控件值的变化

易于单元测试

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对我们的支持。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:基于Vue实现timepicker
下一篇:Spring Boot无缝集成MongoDB
相关文章

 发表评论

暂时没有评论,来抢沙发吧~