Angular Reactive Forms -- Model-Driven Forms响应式表单

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><inputtype="text"placeholder="Your full name"formControlName="name"></label><div formGroupName="account"><label><span>Email address</span><inputtype="email"placeholder="Your email address"formControlName="email"></label><label><span>Confirm address</span><inputtype="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><divclass="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><divclass="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:

@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);}
}

 

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

转载于:https://www.cnblogs.com/xuepei/p/7922022.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/571530.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python实现守护进程_守护进程原理及Python实现

守护进程原理及Python实现守护进程&#xff0c;不依赖于终端&#xff0c;在后台运行的程序&#xff0c;通常称为daemon(ˈdiːmən或ˈdeɪmən)。一些常见的Linux软件通常都是已守护进程的方式运行&#xff0c;比如&#xff1a;nginxredismemcached守护进程的原理&#xff1a;…

python生成器迭代_二十、深入Python迭代器和生成器

「Author&#xff1a;Runsen」学习python的过程中&#xff0c;迭代器与生成器是绕不开的话题&#xff0c; 什么是迭代器和生成器呢&#xff1f;下面我们来了解一下什么是迭代。但在了解迭代器之前&#xff0c;首先需要知道什么是容器。容器正所谓&#xff1a;一切都是对象&…

批改网禁止粘贴怎么破_重大利好!教育部声明,要求家长批改作业等行为,发现一起严处一起...

前段时间&#xff0c;在江苏一位家长发布短视频&#xff0c;他在视频中怒喊&#xff1a;我就退出家长群怎么了&#xff01;引起网上一阵热议起因是这位家长认为老师总是让家长帮忙批改作业&#xff0c;自己承担了太多教师应负的责任&#xff0c;完了还要昧着良心说老师你辛苦了…

mysql实验步骤_MySQL双方配置实验步骤

实验环境&#xff1a;两台MariaDB服务器&#xff0c;IP分别为&#xff1a; 172.16.2.16 和 172.16.2.17MariaDB的版本是5.5.36&#xff0c;使用二进制方式安装。已安装完成。/mydata/data 数据库文件存放目录/mydata/binlog/ 二进制日志文件存放位置/mydata/relaylog/ 中继日志…

mac 系统安装 eclipse 方法

经过好几天的折腾&#xff0c;终于在各种不靠谱的经验、说明的忽悠中把自己心爱的 mac 安装上了 eclipse&#xff0c;看到别人的不靠谱&#xff0c;我决定自己写一篇经验&#xff0c;为了大家能够不走我这么多的弯路&#xff0c;也为了自己将来可以回来看看&#xff0c;下次安装…

python 检测文件更新失败_依赖错误,检测更新失败,提示这个

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼rickrick-PC:~$ sudo apt-get update && sudo apt-get dist-upgrade -y命中:2 https://store.chinauos.com/appstore eagle InRelease获取:1 http://uos.deepin.cn/uos eagle InRelease [20.1 kB]命中:3 http://uos.deepin…

mysql+nest+嵌套事务_MySQL——事务

事务(Transaction)是数据库区别于文件系统的重要特性之一&#xff0c;事务会把数据库从一种一致状态转换为另一种一致状态。关键词事务四大特性ACIDMySql事务隔离级别MVCC多版本并发控制实现方式运行过程MVCC解决了幻读&#xff1f;InnoDB解决幻读的方式事务的分类扁平事务Flat…

谈谈写程序与学英语(转载)

注: 本文的作者是宋劲杉&#xff0c;原文链接。 俗话说&#xff0c;没有金刚钻&#xff0c;就别揽瓷器活儿。套用到IT业&#xff0c;英语不行&#xff0c;就别做程序员。网上关于程序员学英语的文章不少&#xff0c;但我想谈谈我自己的看法。首先详细讨论一下为什么程序员离了英…

python 取日期_python取出所有的日期

python取出所有的日期>>> s "2020-09-09 we have a meeting">>> re.findall([0-9]{4}-[0-9]{2}-[0-9]{2},s)日期的比较2020-09-092020-09-10比较两个日期大小def compare_date(date1,date2) :#取出年&#xff0c;如果同一年#取出月&#xff0c;如…

python自动化和教程_《手把手教你》系列练习篇之2-python+ selenium自动化测试(详细教程)...

1. 简介今天我们还是继续练习练习基本功&#xff0c;各位小伙伴要耐住住性子&#xff0c;要耐得住寂寞啊&#xff0c;不要急躁&#xff0c;后面你会感谢你在前边的不断练习的。到后面也是检验你前边的学习成果的一次很好实践。本文介绍如何通过link text、partial link text、c…

JavaScript高级程序设计之函数表达式

函数表达式是JS中一个强大的特性&#xff0c;尤其是ES6支持Lamada表达式后&#xff0c;更是锦上添花。在前边的文章介绍中&#xff0c;曾经介绍过一种创建函数的方式&#xff0c;函数声明&#xff0c;对函数表达式也有简单介绍。这章将会对函数表达有更详细的介绍。 函数表达式…

异常在哪一层处理_WiFi速度慢,信号不稳定,除了重启路由器外,自己能怎么处理?...

前言WiFi出了故障&#xff0c;速度慢&#xff0c;信号不稳定&#xff0c;自己处理&#xff0c;除了重启路由器&#xff0c;也没有什么别的招了&#xff1b;好在这万能重启&#xff0c;差不多能解决一大半的小故障&#xff1b;那信号不好&#xff0c;速度慢&#xff0c;不稳定&a…

python输入输出代码_python基本输入输出代码示例

#!/usr/bin/env python# -*- coding: utf-8 -*-#输入与输出#str()与repr()for x in range(1, 11):print repr(x).rjust(2), repr(x*x).rjust(3),#逗号代表不换行print repr(x*x*x).rjust(4)#格式化输出for x in range(1, 11):print {0:2d} {1:3d} {2:4d}.format(x, x*x, x*x*x)…

linux运维、架构之路-HAProxy反向代理

一、HAProxy介绍 专业反向代理,支持双机热备支持虚拟主机,配置简单,拥有非常不错的服务器健康检查功能,当其代理的后端节点出现故障, HAProxy会自动将该服务器摘除,故障恢复后再自动将该服务器加入&#xff0c;基于TCP和HTTP应用的代理软件&#xff0c;开源免费、快速并且可靠的…

java洗牌_java语言实现简单的洗牌,发牌

packagecom.java.lei.homework;importjava.util.Arrays;importjava.util.Random;public classPokerGame {//1.创建数组&#xff0c;用以存储扑克牌static String[] pokers new String[54];public static voidmain(String[] args) {//2.创建牌 所有的牌赋值到array数组中pokers…

CSS3 3D transform变换

transform的坐标是需要了解的特性。 我们的rotateX,rotateY,rotateZ,和translateX,translateY等都是基于相同的坐标系来定位的。 3D的坐标如下入所示&#xff1a; 3D transform中有下面这三个方法&#xff1a; rotateX( angle )rotateY( angle )rotateZ( angle )理解了这三个方…

vba结束本次循环进行下次_VBA掌握循环结构,包你效率提高500倍

这是系列免费教程《Excel VBA&#xff1a;办公自动化》&#xff0c;还是老规矩&#xff0c;看看我们走到哪里了。1.认识VBA&#xff1a;什么是VBA&#xff1f;2.这些掌握了&#xff0c;你才敢说自己懂VBA3.VBA变量5年踩坑吐血精华总结4.VBA中重要的强制申明&#xff0c;谁看谁明…

CefSharp 支持MP4

效果图&#xff1a; 下载链接&#xff1a;https://share.weiyun.com/d1e249ef5c56b4d909b2124dc2dd8902 创建Wpf项目引用 如下&#xff1a; 第一步&#xff1a;创建项目引用CefSharp 第二步&#xff1a;将DLL拷贝到运行项目的Debug下 第三步&#xff1a;项目平台设置32位 第四…

python定义字典列表_Python基础语法(四)—列表、元组、字典、集合、字符串

列表基本概念列表是有序的元素集合&#xff0c;所有元素放在一对中括号中&#xff0c;用逗号隔开&#xff0c;没有长度限制&#xff1b;列表索引值以0为开始值&#xff0c;-1为从未尾的开始位置。列表可以使用操作符进行拼接&#xff0c;使用*表示重复。当列表元素增加或删除时…

ReentrantLock 分析

带着疑问去分析 ReentrantLock是如何实现锁管理的。ReentrantLock是如何实现重入的。ReentrantLock是如何实现公平锁与非公平锁。ReentantLock的公平锁为什么一般情况下性能都比公平锁查。ReentrantLock数据结构 ReentrantLock的底层是借助于AbstractQueuedSynchronizer实现的&…