angular之formgroup

文章目录

说明

看到百度上没有特别好的formgroup详解,这里翻译一下,顺便记录下自己的理解

内容

这里直接就搬官网的说明了:

FormGroup 每个子 FormControl
的值聚合到一个对象中,以每个控件名称作为键。它通过减少其子项的状态值来计算其状态。例如,如果组中的某个控件无效,则整个组都将变得无效。

FormGroup 是用于在 Angular 中定义表单的四个基本构建块之一,与 FormControl、FormArray 和
FormRecord 。

实例化 FormGroup 时,请传入子控件的集合作为第一个参数。每个子项的键都会注册控件的名称。

FormGroup 旨在用于提前已知键的用例。如果需要动态添加和删除控件,请改用 FormRecord 。

FormGroup 接受一个可选的类型参数 TControl ,它是一种以内部控件类型作为值的对象类型

构造函数

new FormGroup('默认值',同步验证器,异步验证器)

属性
属性是继承 AbstracControl,下面翻译一下:(这里要说明一下,这里翻译的,都是针对formgroup的,因为对于formArray,formControl可能是不同的)

属性说明
value: TValue控件组的键值对
validator: ValidatorFn | null返回用于同步确定此控件的有效性的函数
asyncValidator: AsyncValidatorFn | null返回用于异步确定此控件的有效性的函数
parent:FormGroup | FormArray | null父控件
status控件的验证状态
valid:boolean当 status 为 VALID 时
invalid: boolean当 status 为 INVALID 时
pending: boolean当 status 为 PENDING 时
disabled: boolean当控件的 status 为 DISABLED 时,禁用的控件免于验证检查,并且不包含在其祖先控件的汇总值中
enabled:boolean同disabled
errors:ValidationErrors | null包含因验证失败生成的任何错误的对象,如果没有错误,则为 null
pristine: boolean如果用户尚未更改 UI 中的值,则控件是 pristine 的
dirty: boolean如果用户更改了 UI 中的值,则控件是 dirty 的
touched: boolean如果控件被标记为 touched ,则为真。一旦用户在其上触发了 blur 事件,则控件就会被标记为已 touched
untouched: booleantouched的相反用法
valueChanges: Observable一种多播 observable,每次控件的值发生更改(在 UI 中或以编程方式)时都会发出事件。它还会在你每次调用 enable() 或 disable() 时发出一个事件,而不将 {emitEvent: false} 作为函数参数传递
statusChanges: Observable每次重新计算控件的验证 status 时都会发出事件的多播 observable。
updateOn: FormHooks报告 AbstractControl 的更新策略(意味着控件更新本身的事件)。可能的值: ‘change’
root: AbstractControl检索此控件的顶级祖先

这里有几个比较难理解的,进行说明一下
1 disabled/enabled
这里需要注意的是,当我们disabled某个控件的时候,在提交表单时,不会进行验证。
在这里插入图片描述
这里密码输入框为DISABLED,在返回的value里面是没有age属性的。并且其状态是DISABLED.

2 valueChanges/statusChanges
这两个用法差不多,这里就讲下valueChanges的用法。这个主要是用来监视表单值变化的,是一个订阅。具体用法如下
在这里插入图片描述
这里呢,在构造函数里,用valueChanges进行数据监控,当name里的数值发生变化时,会订阅这个回调函数。返回的是所有的数据。如果监听单一的数据变化怎么写呢?如下:

 this.validForm.get('name')?.valueChanges.subscribe(data=>{
        debugger
 })

3 updateOn
这个总共有3个默认值’change’ | ‘blur’ | ‘submit’;什么意思呢。就是规定表单的值什么时候进行验证。我们基本都是在输入的时候进行校验,所以默认是change,如果想在点击提交按钮时验证的话,就改成submit。具体写法如下:
在这里插入图片描述

方法

属性说明
registerControl()使用组的控件列表注册控件
addControl()向此组添加控件
removeControl()从此组中删除控件
setControl()替换现有的控件
contains()检查组中是否存在具有给定名称的启用控件
setValue()它接受一个与组结构匹配的对象,以控件名称作为键
patchValue()它接受以控件名称作为键的对象,并尽力将值与组中的正确控件进行匹配
reset()将所有后代标记为 pristine 和 untouched ,并将所有后代的值设置为默认值,如果没有提供默认值,则为 null
getRawValueFormGroup 的聚合值,包括任何禁用的控件

这里举几个例子说明下,用法基本差不多
1 patchValue
html的写法
在这里插入图片描述
TS的写法
在这里插入图片描述
这里梳理下思路:在界面上定义了一组表单,其中年龄这个控件,在初始化时,对其数据进行了监控。那么我们用patchValue对部分数据
进行修改时,可以设置emitEvent属性。当为true时,则在数值改变时,会触发这个订阅,即会进入到valueChanges的回调中。如果设置为false,则不会进入。

这里把其父类的方法也总结下:

方法说明
setValidators()设置此控件上处于活动状态的同步验证器。调用此方法会覆盖任何现有的同步验证器
setAsyncValidators()设置此控件上处于活动状态的异步验证器。调用此方法会覆盖任何现有的异步验证器。
addValidators()向此控件添加一个或多个同步验证器,而不影响其他验证器。
addAsyncValidators()向此控件添加一个或多个异步验证器,而不影响其他验证器。在运行时添加或删除验证器时,你必须调用 updateValueAndValidity() 以使新验证生效。添加已存在的验证器将没有任何效果。
removeValidators()从此控件中删除同步验证器,而不影响其他验证器。
removeAsyncValidators()从此控件中删除异步验证器,而不影响其他验证器。
hasValidator()检查此控件上是否存在同步验证器函数。
hasAsyncValidator()检查此控件上是否存在异步验证器函数。
clearValidators()清空同步验证器列表。
clearAsyncValidators()清空异步验证器列表。
markAsTouched()将控件标记为 touched 。不更改值的焦点和模糊事件会触及控件。
markAllAsTouched()将控件及其所有后代控件标记为 touched 。
markAsUntouched()将控件标记为 untouched
markAsDirty()将控件标记为 dirty 。当通过 UI 更改控件的值时,控件会变脏;
markAsPristine()将控件标记为 pristine 。
markAsPending()将控件标记为 pending 。
disable()禁用控件。这意味着此控件免于验证检查,并从任何父级的聚合值中排除。
enable()同disable
setParent()设置控件的父级
setValue()设置控件的值。抽象方法(在子类中实现)
patchValue()修补控件的值。抽象方法(在子类中实现)。
reset()重置控件。抽象方法(在子类中实现)。
getRawValue()此控件的原始值。对于大多数控件实现,原始值将包括禁用的子项。
updateValueAndValidity()重新计算控件的值和验证状态。
setErrors()手动而不是自动运行验证时,在表单控件上设置错误。
get()
getError()报告具有给定路径的控件的错误数据。
hasError()报告具有给定路径的控件是否具有指定的错误。

推论

关于表单验证,一套完整的复杂的表单验证,其实有很多需要注意的。这里我列举一个在企业中,实际产生的操作。
需求:

我们给一个学校做一个操作系统,其中有一个需求,就是根据班级,筛选出其中的班级总人数,男女人数。这个学校的10班是个特殊班级,只有女生。

在这里插入图片描述
我们的弹出框:
在这里插入图片描述

功能描述:
1 点击添加时,弹出添加弹窗。均可编辑
2 勾选时,弹出编辑弹窗,当选择10班时,隐藏男生条目。并且女生条目不可编辑。

这里稍微用ng-zorro-antd框架美化一下
代码:

这里分两种思维方式去写代码
第一种:
html

<div style="border-bottom: solid 1px rgb(165, 153, 153)">
  <button nz-button style="margin: 10px" nzType="primary">添加</button>
  <button nz-button style="margin: 10px" nzType="default">编辑</button>
</div>
<nz-table #basicTable [nzData]="listOfData">
  <thead>
    <tr>
      <th>班级</th>
      <th>总人数</th>
      <th>男生人数</th>
      <th>女生人数</th>
      <th>操作</th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor="let data of basicTable.data">
      <td>{{ data.class }}</td>
      <td>{{ data.total }}</td>
      <td>{{ data.man }}</td>
      <td>{{ data.woman }}</td>
      <td>
        <a><i nz-icon nzType="edit" nzTheme="outline"></i></a>
        <a><i nz-icon nzType="delete" nzTheme="outline"></i></a>
      </td>
    </tr>
  </tbody>
</nz-table>

在这里插入图片描述
请添加图片描述
其实添加都很简单,初始化表单之后,点击确定,就可以调用ajax把数据传到后台了。那么编辑怎么做呢?其实,编辑要做的就是回显以及初始化数据之后的联动。

TS

 add(){
    this.isVisible=true;
  }
  edit(){
    this.isVisible=true;
  }


  isVisible:boolean=false;
  //取消
  handleCancel(){
    this.isVisible = false
  }
  //确定
  submit() {
    this.isVisible = false
  }

  validForm!: FormGroup;
  constructor(private fb: FormBuilder){}
  ngOnInit(): void {
    this.initForm();
  }
  initForm() {
    this.validForm = this.fb.group({
      class: ['three', [Validators.required]],
      total: ['', [Validators.required]],
      man: ['', [Validators.required]],
      woman: ['', [Validators.required]],
    });
  }
  listOfData = [
    {
      key: '1',
      class: '一班',
      total:50,
      man: 32,
      woman: 18
    },
    {
      key: '4',
      class: '四班',
      total:52,
      man: 32,
      woman: 20
    },
    {
      key: '3',
      class: '三班',
      total:26,
      man: 15,
      woman: 11
    }
  ];
  list = [
    { name: '一班', value: 'one' },
    { name: '二班', value: 'two' },
    { name: '三班', value: 'three' },
    { name: '四班', value: 'four' },
    { name: '五班', value: 'five' },
    { name: '六班', value: 'six' },
    { name: '七班', value: 'seven' },
    { name: '八班', value: 'eight' },
    { name: '九班', value: 'nine' },
    { name: '十班', value: 'ten' },
  ];
  clsChange(e: any) {
    //当班级为ten时,隐藏男生条目,并且女生条目不可编辑
    if (e == 'ten') {
      this.validForm.get('man')?.disable()
      this.validForm.get('woman')?.disable()
    }else{
      this.validForm.get('man')?.enable()
      this.validForm.get('woman')?.enable()
    }
  }

我们已经在clsChange()方法中对表单进行了启用以及禁用的逻辑判断。那么,当我们点击编辑按钮时,我们假设已经通过ajax获取到了后台返回的数据。那么我们需要赋初值了。

假设,我们编辑10班的数据,我修改一下数据后,是这样的:
在这里插入图片描述

但是,发现没有,当手动设置值的时候,男生人数竟然没有自动隐藏。
最后检查发现啊,是clsChange事件没有触发,但是我们知道ngmodelchange是angular内置的绑定事件,在patchvalue中是会被触发的。那只能说明在点击编辑按钮时,dom元素还没有渲染出来;由于我是在onInit里初始化的表单数据,当我把其放到构造函数中发现也不行。那么我们进一步测试,把弹出框的表单独立成一个组件,如下
在这里插入图片描述
父组件的代码:
在这里插入图片描述

最后测试的过程很复杂,就不记录了,把结果告诉大家:

结论:
1 表单回显时,初始化在oninit里面时,调用patchValue不会触发绑定在dom元素上的事件。因为在oninit周期内,dom元素还没有绑定方法。必须在ngafterviewinit里面去调用才可以。这是第一种思维方式。就是把表单联动的逻辑绑定在dom元素上时,调用的生命周期不是Oninit

2 如果不用上面的方法,我们可以利用valueChanges方法,直接监听表单数据,改变时控制其启用禁用状态从而来控制联动效果。我个人认为这样的写法比较好,层次比较分明,业务逻辑比较清晰。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李卓书

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值