模型驱动表单

  之前有篇博文总结了 模版驱动表单 , 以及 模版驱动表单的自定义校验 , 本篇总结下模型驱动表单。

  与模版驱动表单是不同的编程思路,偏向于数据模型。先在组件中建立表单控件的对象树,再绑定到组件模版的原生表单控件上。而模版驱动表单则是在组件模版中使用了内置的 ngForm、ngModel指令,这些指令会自动完成很多工作,以达到双向绑定、监听form和表单控件的状态等等 的目的。虽然模版驱动表单写起来更见的简洁方便,因为指令自动完成了很多工作,但是也正式由于委托指令,所以会导致异步的问题。官网描述 如下:

  1. 响应式表单是同步的而模板驱动表单是异步的。
  2.  
  3. 使用响应式表单,你会在代码中创建整个表单控件树。 你可以立即更新一个值或者深入到表单中的任意节点,因为所有的控件都始终是可用的。
  4.  
  5. 模板驱动表单会委托指令来创建它们的表单控件。 为了消除“检查完后又变化了”的错误,这些指令需要消耗一个以上的变更检测周期来构建整个控件树。 这意味着在从组件类中操纵任何控件之前,你都必须先等待一个节拍。

  虽然目前本人目前使用模版驱动表单,还没有遇到因异步导致的问题,但是也许在某一天,bug会从天而降。

  模型驱动表单需要引入模块 : ReactiveFormsModule  。而模版驱动表单需要引入 FormsModule

  Angular提供了一些方法来构建表单控件的对象树。FormControlFormGroupFormArray是构建表单模型的三种表单类,它们有共同的基类 AbstractControl。这三种表单类有不同的作用。

FormControl

  FormControl用来构建一个单独的表单控件的值和状态,它会对应这模型中的一个表单元素。FormControl类的构造函数如下:

  1. constructor(formState?: any, validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null, asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null);

  接受三个可选参数:初始值、验证器、异步验证器。简单的创建一个formControl

  1. //引入依赖
  2. import { FormControl , Validators} from '@angular/forms';
  3.  
  4. //创建对象 设置初始值,和校验规则
  5. public name = new FormControl('' , Validators.required);

  使用 formControl 可将此控件对象绑定到组件模板中

  1. <input class="form-control" type="text" id="login-name" placeholder="请输入登录帐号" [formControl]="name">
 <div class="form-group">
  {{name.value}} || {{name.status}}
 </div>

  随便输入内容,已经能正确监听控件的值和状态了!每当输入框内容中有变化,name(控件对象)都会随之改变。

  此时都是输入内容变化都会触发控件对象更新,那么如何修改触发更新的时机呢?在FormControl的构造函数中有 AbstractControlOptions ,其中的 updateOn 配置项可以修改触发时机。从源码中可以查看到有三种不同的方式, 值变化,失焦,提交。

  1. // 失焦时触发更新
  2. public name = new FormControl('' , {
  3. validators : Validators.required,
  4. updateOn : 'blur'
  5. });

FormGroup

  FormGroup对象用来跟踪一组 AbstractControl 的值和状态,即可以跟踪多个formControl和FormGroup。构造函数如下:

  1. constructor(controls: {
  2. [key: string]: AbstractControl;
  3. }, validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null, asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null);

  创建一个简单的formGroup,并绑定到模版中

  1. // 简单的formGroup
  2. public loginForm = new FormGroup({
  3. name : new FormControl('', Validators.maxLength(20)),
  4. psw : new FormControl('')
  5. }, Validators.required);
  6.  
  7. // 绑定到模版中
  8. <form class="login-area" (submit)="login()" [formGroup] = "loginForm">
  9. <div class="form-group">
  10. <input class="form-control" type="text" id="login-name" placeholder="请输入登录帐号" formControlName = 'name'>
  11. </div>
  12. <div class="form-group">
  13. <input class="form-control" type="password" id="login-pwd" placeholder="请输入登录密码" formControlName = 'psw'>
  14. </div>
  15. <div class="form-group">
  16. {{loginForm.value | json}}
  17. </div>
  18. </form>

  这里就不能再使用[formControl]来绑定表单控件了,因为这里创建的是FormGroup,已经通过[formGroup]绑定到了 form上了,这你需要通过FormGroup来找到FormControl,在表单控件中用formControlName来指定对应的FormControl对象。

FormBuilder

  以上的方式构建表单对象树太过于繁琐,需要使用很多的new FormGroup() (构建多级表单的时候) 和 new FromControl()  ,FormBuilder就是简化构造方式的的服务。FormBuilder服务中有三个工厂函数 group()  control() array() 可以简化代码量。使用FormBuilder的方式再次构建上面的表单对象树。

  1. public loginForm: FormGroup;
  2.  
  3. constructor(
  4. private fb: FormBuilder
  5. ) {
  this.loginForm = fb.group({
      name : ['' , Validators.required],
      psw : ['']
    }, {
      validator : Validators.minLength(2)
    });
  }

  已经减少了一些代码量,在表单很庞大的时候,对比会特别明显。注意group工具函数指定表单组的校验规则时与原new GroupForm()参数放置的位置不一样。

  1. /**
  2. * Construct a new {@link FormGroup} with the given map of configuration.
  3. * Valid keys for the `extra` parameter map are `validator` and `asyncValidator`.
  4. *
  5. * See the {@link FormGroup} constructor for more details.
  6. */
  7. group(controlsConfig: {
  8. [key: string]: any;
  9. }, extra?: {
  10. [key: string]: any;
  11. } | null): FormGroup;

多级FormGroup

  为了更高效的管理表单,可以把类似的表单放在一起,形成一个FormGroup,这样就可以同时管理这些类似表单的值和状态。这样创建就会产生多级FormGroup。再通过formGroupName把子group导向模版中。

  1. this.loginForm = fb.group({
  2. name: this.fb.group({
  3. firstname: ['' , Validators.required],
  4. lastname: ''
  5. }),
  6. psw: ['' , Validators.required]
  7. });
  8.  
  9. <div formGroupName="name">
  10. <div class="form-group">
  11. <input class="form-control" type="text" id="login-name" placeholder="请输入姓" formControlName = 'firstname'>
  12. </div>
  13. <div class="form-group">
  14. <input class="form-control" type="text" id="login-name" placeholder="请输入名" formControlName = 'lastname'>
  15. </div>
  16. </div>

获取控件状态

  在FormGroup中可以通过get()方法定位到表单控件对象,然后就能够获取到各种状态了,和之前模版驱动表单中介绍的一样。可以简单的封装一个获取函数,这样在模版中就能非常方便的获取到各个formControl。

  1. getFormControl(name: string) {
  2. return this.loginForm.get(name);
  3. }
  4.  
  5. <div class="form-group">
  6. {{getFormControl('name').status}}
  7. </div>
  8. <div class="form-group">
  9. {{getFormControl('name.firstname').status}}
  10. </div>

自定义校验

  模型驱动表单的自定义校验方便很多,因为可以直接自定义各级formControl。以上面的多级group为例,添加定义的校验规则:firstname和lastname不能输入相同的值。

  1. sameName (): ValidatorFn {
  2. return (control: AbstractControl): { [key: string]: any} => { // control指向使用它的formControl或者formGroup
  3. return control.get('firstname').value === control.get('lastname').value ? { 'sameName' : true } : null; // 子formcontrol的值相同就返回错误
  4. };
  5. }

  在模型中使用此校验规则

  1. this.loginForm = fb.group({
  2. name: this.fb.group({
  3. firstname: ['' , Validators.required],
  4. lastname: ['']
  5. } , {
  6. validator : [ // 对整个name的校验规则
  7. this.sameName(), Validators.minLength(2)
  8. ]
  9. }),
  10. psw: ['' , Validators.required]
  11. });

Angular使用总结 --- 模型驱动表单的更多相关文章

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

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

  2. Angular将填入表单的数据渲染到表格

    一.项目简介 我们将采用Angular框架来做一个demo,这个demo将要实现的功能如下: 在X坐标和Y坐标文本框输入信息,然后点击添加,就会在下面表格 中出现一项相应的数据,点击每一项旁边的删除按 ...

  3. angular 响应式自定义表单控件—注册头像实例

    1. 组件继承ControlValueAccessor,ControlValueAccessor接口需要实现三个必选方法 writeValue() 用于向元素中写入值,获取表单的元素的元素值 regi ...

  4. Angular Reactive Form - 填充表单模型

    setValue 使用setValue,可以通过传递其属性与FormGroup后面的表单模型完全匹配的数据对象来一次分配每个表单控件值. 在分配任何表单控件值之前,setValue方法会彻底检查数据对 ...

  5. angular $http 与form表单的select-->refine

    <!DOCTYPE html> <html ng-app="a2_15"> <head> <meta http-equiv="C ...

  6. angular $http 与form表单的select

    产品线 产品 版本 代码是联动关系 ng-model 绑定数据 设置默认值 ng-options 填充option ng-change 选项变化时的操作截图如下: html <!DOCTYPE ...

  7. Angular使用总结 --- 模版驱动表单

    表单的重要性就不多说了,Angular支持表单的双向数据绑定,校验,状态管理等,总结下. 获取用户输入 <div class="container-fluid login-page&q ...

  8. angular表单知识点

    原文 https://www.jianshu.com/p/c772d143e1fc 大纲 1.对表单的理解 2.模板驱动表单(Template Driven Forms) 3.响应式表单(Reacti ...

  9. 从浅入深剖析angular表单验证

    最近手上维护的组件剩下的BUG都是表单验证,而且公司的表单验证那块代码经历的几代人,里面的逻辑开始变得不清晰,而且代码结构不是很angular. 是很有必要深入了解表单验证. 入门之前,我觉得应该先了 ...

随机推荐

  1. Vue.directive基础,在Vue模块开发中使用

    这是从网上找到的一个案例,由于网上的案例有坑,所以我在这里从新上传一次! 首先在main.js里引入两个自定义指令 import {focus, drag} from './components/da ...

  2. chattr改变文件属性

    Linux chattr命令用于改变文件属性. 这项指令可改变存放在ext2文件系统上的文件或目录属性,这些属性共有以下8种模式: a:让文件或目录仅供附加用途. b:不更新文件或目录的最后存取时间. ...

  3. 如何将mysql卸载干净

    一.在控制面板中卸载mysql软件 二.卸载过后删除C:\Program Files (x86)\MySQL该目录下剩余了所有文件,把mysql文件夹也删了 三.windows+R运行“regedit ...

  4. ibatis注意要点

    一.ibatis的关键字like查询 select * from t_student where s_name '%张%'; 这种like语句在ibatis中怎么写,他们现在的项目是用ibatis作为 ...

  5. svn更新的时候出现ERROR:Previous operation has not finished,run "clean up" if it wa interrupted;进行clean up命令也报错

    报错的截图: 然后进行了clean up命令,依旧报错了: 这种情况就有两种方法去解决了,自己可以根据自己的情况选择,哪种方便选择哪种呗! 方法一: 备份自己修改的文件,删除之前download的文件 ...

  6. 代码的二次重构(开篇:JDBC连接数据库)

    Java中使用JDBC连接数据库时,若是使用初级的代码,代码复用率非常低,连接过程简单来说分为以下几个步骤: 加载驱动包 准备好URL链接获取数据库连接(driver和url根据不同的数据库的不同而不 ...

  7. DDR中的一些知识点说明(ODT,ZQ校准,OCT,TDQS)

    ODT ( On-DieTermination ,片内终结)ODT 也是 DDR2 相对于 DDR1 的关键技术突破,所谓的终结(端接),就是让信号被电路的终端吸 收掉,而不会在电路上形成反射, 造成 ...

  8. 20171126-handler消息机制理解

    1.handler消息机制的理解 http://www.jianshu.com/p/8343a39b8a2c?s_q_s_h_a_r_e_1MTAzNTIwODAxNTExNTg5NTkwMzE0Nz ...

  9. activeMq之hello(java)

    消息队列activeMq,   节省响应时间,解决了第三方响应时间长的问题让其他客户可以继续访问, 安装activeMq apache-activemq-5.14.0-bin\apache-activ ...

  10. noip第23课作业

    1.   营救 铁塔尼号遇险了!他发出了求救信号.距离最近的哥伦比亚号收到了讯息,时间就是生命,必须尽快赶到那里. 通过侦测,哥伦比亚号获取了一张海洋图.这张图将海洋部分分化成n*n个比较小的单位,其 ...