angular formgroup

Article directory

illustrate

Seeing that there is no particularly good detailed explanation of formgroup on Baidu, I will translate it here and record my understanding by the way.

content

Here are the instructions from the official website:

FormGroup The values ​​of each child FormControl
are aggregated into a single object, with each control name as the key. It calculates its status by decrementing the status values ​​of its children. For example, if a control in a group is invalid, the entire group becomes invalid.

FormGroup is one of the four basic building blocks for defining forms in Angular, along with FormControl, FormArray, and
FormRecord.

When instantiating a FormGroup, pass in a collection of child controls as the first parameter. Each child's key registers the name of the control.

FormGroup is intended for use cases where the keys are known ahead of time. If you need to add and remove controls dynamically, use FormRecord instead.

FormGroup accepts an optional type parameter TControl, which is an object type with the internal control type as the value

Constructor

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

Properties
The properties inherit from AbstractControl. Please translate them below: (I would like to explain here that the translations here are all for formgroup, because formArray and formControl may be different)

Attributes illustrate
value: TValue The key-value pair of the control group
validator: ValidatorFn | null Returns a function used to synchronously determine the validity of this control
asyncValidator: AsyncValidatorFn | null Returns a function used to asynchronously determine the validity of this control
parent:FormGroup | FormArray | null parent control
status The validation status of the control
valid:boolean When status is VALID
invalid: boolean When status is INVALID
pending: boolean When status is PENDING
disabled: boolean When a control's status is DISABLED, a disabled control is exempt from validation checks and is not included in the aggregate value of its ancestor controls
enabled:boolean Same disabled
errors:ValidationErrors | null An object containing any errors generated due to validation failures, or null if there were no errors
pristine: boolean If the user has not changed the value in the UI, the control is pristine
dirty: boolean If the user changes the value in the UI, the control is dirty
touched: boolean True if the control is marked touched. Once the user triggers the blur event on it, the control is marked as touched
untouched: boolean Opposite usage of touched
valueChanges: Observable A multicast observable that emits events every time a control's value changes (either in the UI or programmatically). It also emits an event every time you call enable() or disable() without passing {emitEvent: false} as a function argument
statusChanges: Observable A multicast observable that emits events each time the control's validation status is recalculated.
updateOn: FormHooks Reports the AbstractControl's update strategy (meaning the event that the control updates itself). Possible values: 'change'
root: AbstractControl Retrieve the top-level ancestors of this control

There are a few that are difficult to understand here, let’s explain them
1 disabled/enabled
What needs to be noted here is that when we disable a certain control, verification will not be performed when submitting the form.
Insert image description here
The password input box here is DISABLED, and there is no age attribute in the returned value. and its status is DISABLED.

2 The two usages of valueChanges/statusChanges
are similar. Here I will talk about the usage of valueChanges. This is mainly used to monitor changes in form values ​​and is a subscription. The specific usage is as follows.
Insert image description here
Here, in the constructor, use valueChanges for data monitoring. When the value in name changes, this callback function will be subscribed. All data is returned. How to write if you monitor a single data change? as follows:

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

3 updateOn
has a total of 3 default values ​​'change' | 'blur' | 'submit'; what does it mean? It is to specify when the form value will be verified. We basically perform verification when typing, so the default is change. If you want to verify when clicking the submit button, change it to submit. The specific writing method is as follows:
Insert image description here

method

Attributes illustrate
registerControl() Register controls using a group's control list
addControl() Add controls to this group
removeControl() Remove controls from this group
setControl() Replace existing controls
contains() Checks whether an enabled control with the given name exists in the group
setValue() It accepts an object matching the group structure, with the control name as key
patchValue() It accepts objects with control names as keys and does its best to match the values ​​to the correct control in the group
reset() Mark all descendants as pristine and untouched, and set the value of all descendants to the default value, or null if no default value is provided
getRawValue The aggregate value of the FormGroup, including any disabled controls

Here are a few examples to illustrate. The usage is basically the same.
1
How to write patchValue html How to
Insert image description here
write TS
Insert image description here
Here is a summary of the ideas: A set of forms is defined on the interface, and the age control is monitored during initialization.
Then when we use patchValue to modify some data , we can set the emitEvent attribute. When it is true, this subscription will be triggered when the value changes, that is, it will enter the callback of valueChanges. If set to false, it will not be entered.

Here is a summary of the methods of its parent class:

method illustrate
setValidators() Sets the active sync validator on this control. Calling this method overwrites any existing sync validators
setAsyncValidators() Sets the active asynchronous validator on this control. Calling this method overwrites any existing asynchronous validators.
addValidators() Adds one or more synchronous validators to this control without affecting other validators.
addAsyncValidators() Adds one or more asynchronous validators to this control without affecting other validators. When adding or removing validators at runtime, you must call updateValueAndValidity() for the new validation to take effect. Adding an existing validator will have no effect.
removeValidators() Removes the synchronous validator from this control without affecting other validators.
removeAsyncValidators() Removes an asynchronous validator from this control without affecting other validators.
hasValidator() Checks if a synchronous validator function exists on this control.
hasAsyncValidator() Checks if an async validator function exists on this control.
clearValidators() Clear the sync validator list.
clearAsyncValidators() Clear the async validator list.
markAsTouched() Mark the control as touched. Focus and blur events touch the control without changing the value.
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班是个特殊班级,只有女生。

Insert image description here
我们的弹出框:
Insert image description here

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

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

There are two ways of thinking about writing code.
The first one:
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>

Insert image description here
Please add image description
In fact, adding is very simple. After initializing the form, click OK, and you can call ajax to transfer the data to the background. So what does an editor do? In fact, what the editor needs to do is echo and linkage after initializing the data.

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()
    }
  }

We have made logical judgments about enabling and disabling the form in the clsChange() method. Then, when we click the edit button, we assume that we have obtained the data returned by the background through ajax. Then we need to assign an initial value.

Suppose we edit the data of class 10. After I modify the data, it looks like this:
Insert image description here

However, I found that no, when the value was manually set, the number of boys was not automatically hidden.
The final check revealed that the clsChange event was not triggered, but we know that ngmodelchange is Angular's built-in binding event and will be triggered in patchvalue. That only means that when the edit button is clicked, the dom element has not been rendered; since I initialized the form data in onInit, it didn't work when I put it in the constructor. Then we further test and separate the pop-up box form into a component, as follows:
Insert image description here
The code of the parent component:
Insert image description here

The final test process is very complicated, so I will not record it. I will tell you the results:

Conclusion:
1 When the form is echoed and initialized in oninit, calling patchValue will not trigger the event bound to the dom element. Because during the oninit cycle, the dom element has no binding method yet. It must be called in ngafterviewinit. This is the first way of thinking. That is, when the logic of form linkage is bound to the dom element, the life cycle of the call is not Oninit

2. If the above method is not used, we can use the valueChanges method to directly monitor the form data and control its enabled and disabled status when it changes to control the linkage effect. . I personally think this way of writing is better, with clearer levels and clearer business logic.

Guess you like

Origin blog.csdn.net/wangbiao9292/article/details/126446112