Angular 4.x 中有两种表单:

  • Template-Driven Forms - 模板驱动式表单 (类似于 AngularJS 1.x 中的表单 )  官方文档:https://v2.angular.cn/docs/ts/latest/guide/forms.html

  • Reactive Forms (Model-Driven Forms) - 响应式表单  官方文档: https://v2.angular.cn/docs/ts/latest/guide/reactive-forms.html

Template-Driven Forms vs Reactive Forms

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

  • 使用方便

  • 适用于简单的场景

  • 通过 [(ngModel)] 实现数据双向绑定

  • 最小化组件类的代码

  • 不易于单元测试

  • 异步的,模板驱动表单会委托指令来创建它们的表单控件。 为了消除“检查完后又变化了”的错误,这些指令需要消耗一个以上的变更检测周期来构建整个控件树。 这意味着在从组件类中操纵任何控件之前,我们都必须先等待一个节拍。

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

  • 比较灵活

  • 适用于复杂的场景

  • 简化了HTML模板的代码,把验证逻辑抽离到组件类中

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

  • 易于单元测试

  • 同步的 ,使用响应式表单,我们会在代码中创建整个表单控件树。 我们可以立即更新一个值或者深入到表单中的任意节点,因为所有的控件都始终是可用的。

使用 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。

FormControl 和 FormGroup

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

使用示例:

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

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'

User interface

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 接口来获取表单的初始信息。

绑定FormGroup模型

<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()]),
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 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()]),
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:

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

转自:https://segmentfault.com/a/1190000009041192

Angular Reactive Forms -- Model-Driven Forms响应式表单的更多相关文章

  1. ng2响应式表单-翻译与概括官网REACTIVE FORMS页面

    本文将半翻译半总结的讲讲ng2官网的另一个未翻译高级教程页面. 原文地址. 文章目的是使用ng2提供的响应式表单技术快速搭出功能完善丰富的界面表单组件. 响应式表单是一项响应式风格的ng2技术,本文将 ...

  2. Angular2响应式表单-翻译与概括官网REACTIVE FORMS页面

    本文将半翻译半总结的讲讲ng2官网的另一个未翻译高级教程页面. 原文地址. 文章目的是使用ng2提供的响应式表单技术快速搭出功能完善丰富的界面表单组件. 响应式表单是一项响应式风格的ng2技术,本文将 ...

  3. Angular11 模板表单、响应式表单(自定义验证器)、HTTP、表单元素双向绑定

    1 模板表单 模型通过指令隐式创建 技巧01:需要在模块级别引入 FormsModule ,通常在共享模块中引入再导出,然后在需要用到 FormsModule 的模块中导入共享模块就可以啦 impor ...

  4. Angular2响应式表单

    本文将半翻译半总结的讲讲ng2官网的另一个未翻译高级教程页面. 原文地址. 文章目的是使用ng2提供的响应式表单技术快速搭出功能完善丰富的界面表单组件. 响应式表单是一项响应式风格的ng2技术,本文将 ...

  5. angular6的响应式表单

    1:在AppModule模块里面引入 ReactiveFormsModule 要使用响应式表单,就要从@angular/forms包中导入ReactiveFormsModule,并把它添加到你的NgM ...

  6. Angular之响应式表单 ( Reactive Forms )

    项目结构 一 首页 ( index.html ) <!doctype html> <html lang="en"> <head> <met ...

  7. 【译】用 Chart.js 做漂亮的响应式表单

    数据包围着我们.虽然搜索引擎和其他应用都对基于文本方式表示的数据偏爱有加,但人们发现可视化是更容易理解的一种方式.今年初,SitePoint 发表了 Aurelio 的文章< Chart.js简 ...

  8. angular响应式表单 - 状态字段

    用于表单验证的过程: touched,untoched pristine,dirty pending

  9. angular 响应式表单

随机推荐

  1. SQL语句的增删改查(详细)

    摘录自:http://blog.csdn.net/a88055517/article/details/6736284 一.增:有2种方法 1.使用insert插入单行数据: 语法:insert [in ...

  2. POJ 3710:Matrix Power Series

    Description 给出矩阵 \(n*n\) 的 矩阵\(A\) , 求 \(A^1+A^2+A^3...+A^k\) Solution 首先我们设 \(S_n=\sum_{i=1}^{n}A^i ...

  3. SQL Serever学习8——数据表3

    创建索引 索引就像是字典的目录一样,可以快速的指定需要的数据. 有没有索引的区别 一个没有索引的集合,如果我们需要查找某一个对象,需要遍历整个集合,直到找到匹配的对象,整个工作费时费力,这只是找一个对 ...

  4. php访问mysql数据库的步骤

    官方说5.5开始就废弃mysql_query()这块东西很多,当然常用的就几个还是看手册吧. 这里简单记录一下.在我失忆之后可以找回一点记忆.最近一直用框架原生的都快忘了. 1.打开mysql连接 $ ...

  5. .Net平台技术介绍、C#语言

    转载别人的  只是用做学习 一.什么是.Net平台? .Net平台是微软搭建的技术平台,技术人员在此平台上进行应用的搭建与开发.它提供了运行所必须的环境.NET Framework类库以及CLR(公共 ...

  6. linux的目录结构及文件基本操作

    1. linux的文件组织目录结构 linux的目录与window的区别 win以存储介质为主,主要以盘符及分区实现文件 管理,再下面才是目录. linux以树形目录结构的形式来构造整个系统,每一个目 ...

  7. springMVC 静态资源加版本号

    springMVC 静态资源加版本号 http://blog.csdn.net/zhangt85/article/details/42126275

  8. CodeForces 606A(水)

    这道题之前没注意到at least,审题不仔细啊,两个问题解法还是有些许区别的 有at least的 #include <iostream> #include <string> ...

  9. yum只下载不安装dokcer

    yum install --downloadonly --downloaddir=/test/ docker-io 有三个依赖包,如果不知道现后依赖顺序,可以强制安装 哦了

  10. webpack打包踩坑之TypeError: Cannot read property 'bindings' of null

    file loader介绍:https://www.webpackjs.com/loaders/file-loader/ babel loader介绍:https://webpack.js.org/l ...