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. 基于 Annotation 的 Spring AOP 权限验证方法的实现

    1. 配置 applicationContext 在 Spring 中支持 AOP 的配置非常的简单,只需要在 Spring 配置文件 applicationContext.xml 中添加: < ...

  2. WCF中的AddressHeader作用

    客户端发送请求给服务端,服务端根据请求消息把消息转发给对应的终结点.这里面有个消息筛选机制,如果请求消息中带有地址报头相关信息,则会用地址报头匹配当前的所有终结点.所以默认情况下客户端和服务端的地址报 ...

  3. 如何快速备份还原Sql Server 数据库

    备份数据库 选择你要备份的数据库,鼠标右键单击,选择任务-备份 弹出备份数据库窗口,选择添加 弹出选择备份目标窗口,点击浏览,选择存放备份数据库的目录,输入文件名,后缀名输入.bak,点击确定,确定, ...

  4. 怎么让一段xml被识别为字符串

    public static String decodeString(String strData) { strData = replaceString(strData, "<" ...

  5. 二、cent OS安装配置tomcat

    下载tomcat的tar包http://tomcat.apache.org/download-80.cgi 确保安装前已经安装JDKjava -version如果没有安装可以参考上一篇文章:http: ...

  6. uwsgi/uWSGI/WSGI简介

    参考文章 uWSGI是一个Web服务器,它实现了WSGI协议.uwsgi.http等协议.Nginx中HttpUwsgiModule的作用是与uWSGI服务器进行交换.z WSGI是一种Web服务器网 ...

  7. SSH文件上传代码片段

    一.文件上传限制: 在web.xml中配置Struts前端控制器时,设置初始化参数:如下图所示 二.controller代码 @Namespace("/") @ParentPack ...

  8. 在弹框中获取foreach中遍历的id值,并传递给地址栏(方法2)

    1.php有时候我们需要再弹框中获取foreach中遍历的数据(例如id),在弹框中点击按钮并传递给地址栏跳转.那么应该怎么做呢.第二种方法. 2. 可以在弹框中给出一个input hidden 点击 ...

  9. grunt-contrib-watch 监控 JS 文件改变来运行预定义的Tasks

    依赖于 GruntJs ~0.4.0 监控 JS 文件改变来运行预定义的Tasks Demo: watch: { scripts: { files: ['src/**/*.js'], tasks: [ ...

  10. 闲谈:乌云上那些 web-based 的 QQ 漏洞

    0×00 起始 昨日凌晨,看到爱尖刀团队发布了一条“腾讯客户端XSS,已第一时间提交至TSRC”的微博,心想,腾讯又出此类漏洞了.今日,由于有一位名叫“阿布”的同学将该漏洞发布到了乌云,引来不少争吵甚 ...