为了账号安全,请及时绑定邮箱和手机立即绑定

Angular使用总结 --- 模型驱动表单

标签:
AngularJS

模型驱动表单

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

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

复制代码

响应式表单是同步的而模板驱动表单是异步的。

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

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

复制代码

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

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

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

FormControl

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

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

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

复制代码

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

复制代码

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

<input class="form-control" type="text"  id="login-name" placeholder="请输入登录帐号">

 <div class="form-group">

  {{name.value}} || {{name.status}}

 </div>

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

https://img1.sycdn.imooc.com//5b3637de000125c605460184.jpg

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

https://img1.sycdn.imooc.com//5b3637e800019dc908150156.jpg

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

FormGroup

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

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

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

复制代码

 // 简单的formGroup  public loginForm = new FormGroup({
    name : new FormControl('', Validators.maxLength(20)),
    psw : new FormControl('')
  }, Validators.required);// 绑定到模版中
  <form class="login-area" (submit)="login()" [formGroup] = "loginForm">
    <div class="form-group">
        <input class="form-control" type="text"  id="login-name" placeholder="请输入登录帐号" formControlName = 'name'>
    </div>
    <div class="form-group">
      <input class="form-control" type="password"  id="login-pwd" placeholder="请输入登录密码" formControlName = 'psw'>
    </div>
    <div class="form-group">
      {{loginForm.value | json}}    </div>
  </form>

复制代码

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

FormBuilder

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

复制代码

  public loginForm: FormGroup;

  constructor(
    private fb: FormBuilder
  ) {

  this.loginForm = fb.group({

      name : ['' , Validators.required],

      psw : ['']

    }, {

      validator : Validators.minLength(2)

    });

  }

复制代码

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

复制代码

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

复制代码

 

多级FormGroup

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

复制代码

    this.loginForm = fb.group({      name: this.fb.group({
        firstname: ['' , Validators.required],
        lastname: ''
      }),
      psw: ['' , Validators.required]
    });  
  <div formGroupName="name"> 
        <div class="form-group">
            <input class="form-control" type="text"  id="login-name" placeholder="请输入姓" formControlName = 'firstname'>
        </div>
        <div class="form-group">
            <input class="form-control" type="text"  id="login-name" placeholder="请输入名" formControlName = 'lastname'>
        </div>
    </div>

复制代码

 

获取控件状态

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

复制代码

    getFormControl(name: string) {
        return this.loginForm.get(name);
   } 

   <div class="form-group">
        {{getFormControl('name').status}}    </div>
    <div class="form-group">
        {{getFormControl('name.firstname').status}}    </div>

复制代码

 

自定义校验

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

复制代码

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

复制代码

  在模型中使用此校验规则

复制代码

    this.loginForm = fb.group({
      name: this.fb.group({
        firstname: ['' , Validators.required],
        lastname: ['']
      } , {
        validator : [ // 对整个name的校验规则
          this.sameName(), Validators.minLength(2)
        ]
      }),
      psw: ['' , Validators.required]
    });

复制代码

原文出处

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消