Angular 4.x中表单Reactive Forms详解
发布时间 - 2026-01-11 00:49:46 点击率:次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
<form novalidate> <label> <span>Full name</span> <input type="text" name="name" placeholder="Your full name"> </label> <div> <label> <span>Email address</span> <input type="email" name="email" placeholder="Your email address"> </label> <label> <span>Confirm address</span> <input type="email" name="confirm" placeholder="Confirm your email address"> </label> </div> <button type="submit">Sign up</button> </form>
接下来我们要实现的功能如下:
- 绑定 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: `
<form novalidate>...</form>
`
})
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 实例,接下来我们来看一下如何使用:
<form novalidate [formGroup]="myGroup"> Name: <input type="text" formControlName="name"> Location: <input type="text" formControlName="location"> </form>
注意事项: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 元素上了。具体示例如下:
<form novalidate [formGroup]="user"> <label> <span>Full name</span> <input type="text" placeholder="Your full name" formControlName="name"> </label> <div formGroupName="account"> <label> <span>Email address</span> <input type="email" placeholder="Your email address" formControlName="email"> </label> <label> <span>Confirm address</span> <input type="email" placeholder="Confirm your email address" formControlName="confirm"> </label> </div> <button type="submit">Sign up</button> </form>
现在 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 输出属性,处理表单的提交逻辑:
<form novalidate (ngSubmit)="onSubmit(user)" [formGroup]="user"> ... </form>
需要注意的是:我们使用 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 属性。接下来我们来添加表单验证失败时,不允许进行表单提交功能:
<form novalidate (ngSubmit)="onSubmit(user)" [formGroup]="user"> ... <button type="submit" [disabled]="user.invalid">Sign up</button> </form>
那么问题来了,我们要如何获取表单控件的验证信息?我们可以使用模板驱动表单中介绍的方式,具体如下:
<form novalidate [formGroup]="user">
{{ user.controls.name?.errors | json }}
</form>
友情提示: ?.prop 称为安全导航操作符,用于告诉 Angular prop 的值可能不存在。
此外我们也可以使用 FormGroup 对象提供的 API,来获取表单控件验证的错误信息:
<form novalidate [formGroup]="user">
{{ user.get('name').errors | json }}
</form>
现在我们来看一下完整的代码:
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { User } from './signup.interface';
@Component({
selector: 'signup-form',
template: `
<form novalidate (ngSubmit)="onSubmit(user)" [formGroup]="user">
<label>
<span>Full name</span>
<input type="text" placeholder="Your full name" formControlName="name">
</label>
<div class="error" *ngIf="user.get('name').hasError('required') &&
user.get('name').touched">
Name is required
</div>
<div class="error" *ngIf="user.get('name').hasError('minlength') &&
user.get('name').touched">
Minimum of 2 characters
</div>
<div formGroupName="account">
<label>
<span>Email address</span>
<input type="email" placeholder="Your email address" formControlName="email">
</label>
<div
class="error"
*ngIf="user.get('account').get('email').hasError('required') &&
user.get('account').get('email').touched">
Email is required
</div>
<label>
<span>Confirm address</span>
<input type="email" placeholder="Confirm your email address"
formControlName="confirm">
</label>
<div
class="error"
*ngIf="user.get('account').get('confirm').hasError('required') &&
user.get('account').get('confirm').touched">
Confirming email is required
</div>
</div>
<button type="submit" [disabled]="user.invalid">Sign up</button>
</form>
`
})
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模板的代码,把验证逻辑抽离到组件类中
- 方便的跟踪表单控件值的变化
- 易于单元测试
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对的支持。
# reactive
# forms
# angular
# angularjs
# 表单
# React中使用async validator进行表单验证的实例代码
# ReactJS实现表单的单选多选和反选的示例
# 详解Angular Reactive Form 表单验证
# 基于React实现表单数据的添加和删除详解
# 通过实例学习React中事件节流防抖
# React中阻止事件冒泡的问题详析
# 详解react关于事件绑定this的四种方式
# React.Js添加与删除onScroll事件的方法详解
# 在React中如何优雅的处理事件响应详解
# 详解Python的Twisted框架中reactor事件管理器的用法
# 详细分析React 表单与事件
# 我们可以
# 绑定
# 可以使用
# 让我们
# 适用于
# 我们必须
# 友情提示
# 输入框
# 的是
# 这是
# 单元测试
# 来了
# 可用于
# 过了
# 上了
# 我有
# 不需要
# 就好
# 两种
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
rsync同步时出现rsync: failed to set times on “xxxx”: Operation not permitted
详解Android图表 MPAndroidChart折线图
免费网站制作appp,免费制作app哪个平台好?
香港服务器网站推广:SEO优化与外贸独立站搭建策略
图册素材网站设计制作软件,图册的导出方式有几种?
ai格式如何转html_将AI设计稿转换为HTML页面流程【页面】
香港服务器租用费用高吗?如何避免常见误区?
武汉网站设计制作公司,武汉有哪些比较大的同城网站或论坛,就是里面都是武汉人的?
重庆市网站制作公司,重庆招聘网站哪个好?
成都品牌网站制作公司,成都营业执照年报网上怎么办理?
Laravel怎么使用artisan命令缓存配置和视图
香港服务器WordPress建站指南:SEO优化与高效部署策略
网站页面设计需要考虑到这些问题
微信h5制作网站有哪些,免费微信H5页面制作工具?
深圳网站制作设计招聘,关于服装设计的流行趋势,哪里的资料比较全面?
高性价比服务器租赁——企业级配置与24小时运维服务
长沙做网站要多少钱,长沙国安网络怎么样?
如何做网站制作流程,*游戏网站怎么搭建?
如何用5美元大硬盘VPS安全高效搭建个人网站?
韩国代理服务器如何选?解析IP设置技巧与跨境访问优化指南
百度浏览器网页无法复制文字怎么办 百度浏览器复制修复
Win11关机界面怎么改_Win11自定义关机画面设置【工具】
Laravel如何使用Service Provider服务提供者_Laravel依赖注入与容器绑定【深度】
Laravel Seeder填充数据教程_Laravel模型工厂Factory使用
手机钓鱼网站怎么制作视频,怎样拦截钓鱼网站。怎么办?
Java解压缩zip - 解压缩多个文件或文件夹实例
Laravel如何使用Service Provider注册服务_Laravel服务提供者配置与加载
什么是javascript作用域_全局和局部作用域有什么区别?
Laravel Docker环境搭建教程_Laravel Sail使用指南
Android 常见的图片加载框架详细介绍
Laravel如何实现一对一模型关联?(Eloquent示例)
laravel怎么通过契约(Contracts)编程_laravel契约(Contracts)编程方法
网站制作价目表怎么做,珍爱网婚介费用多少?
手机怎么制作网站教程步骤,手机怎么做自己的网页链接?
Laravel任务队列怎么用_Laravel Queues异步处理任务提升应用性能
Android GridView 滑动条设置一直显示状态(推荐)
香港服务器部署网站为何提示未备案?
如何在云服务器上快速搭建个人网站?
如何快速搭建高效WAP手机网站?
如何在建站宝盒中设置产品搜索功能?
网站视频制作书签怎么做,ie浏览器怎么将网站固定在书签工具栏?
Laravel如何实现事件和监听器?(Event & Listener实战)
Laravel怎么实现模型属性的自动加密
如何确保西部建站助手FTP传输的安全性?
Laravel如何记录自定义日志?(Log频道配置)
什么是JavaScript解构赋值_解构赋值有哪些实用技巧
米侠浏览器网页背景异常怎么办 米侠显示修复
phpredis提高消息队列的实时性方法(推荐)
Laravel Asset编译怎么配置_Laravel Vite前端构建工具使用
logo在线制作免费网站在线制作好吗,DW网页制作时,如何在网页标题前加上logo?

