Angular10--表单

438 阅读2分钟

Angular表单中的FormControl、FormGroup、FormBuilder、FormArray

要使用响应式表单,首先需要在@angular/forms包导入ReactiveFormsModule,并把它放到ngModule的imports数组中去。

app.module.ts

import { ReactiveFormsModule } from '@angular/forms';

@NgModule({
  imports: [
    ReactiveFormsModule,    //<==
    CommonModule
  ],
  ...
})

如果要获得control,还要在component中加入


@Component({
  ...
  selector: 'app-test-array',
  providers: [{
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => TestArrayComponent),
    multi: true,
  }]
})
export class TestArrayComponent{
  ...
}

1、FormControl

FormControl封装了字段的值和状态,比如是否有效、是否脏(被修改过)、是否有错误等等 test-control.component.ts

import { Component, OnInit } from '@angular/core';
import {FormControl, Validators } from '@angular/forms';

@Component({
  selector: 'app-test-control',
  templateUrl: './test-control.component.html',
  styleUrls: ['./test-control.component.css'],
})
export class TestControlComponent{
  outside =  new FormControl('xxxx', [Validators.required])
  getValue(){
    console.log(this.outside.value);
  }
}

test-control.component.html

<div>
  测试control:
  <span *ngIf="outside?.invalid">不能为空 </span>
  <input [formControl]="outside" placeholder="Last name">
  <button (click)="getValue()">getvalue</button>
</div>

2、FormGroup

test-group.component.ts

import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { checkNameValidator } from '../myname.validator';

@Component({
  selector: 'app-test-group',
  templateUrl: './test-group.component.html',
  styleUrls: ['./test-group.component.css']
})
export class TestGroupComponent{
  form: FormGroup = new FormGroup({
    first:  new FormControl('lili', {
      validators: [Validators.required, Validators.maxLength(5)], 
      asyncValidators: checkNameValidator(),
      updateOn: 'blur'
    }),
    last:  new FormControl({value: 'xxx', disabled: true, })
  })

  onSubmit(): void{
    console.log(this.form.value);
  }
  get first(): any {
    return this.form.get('first');
  }
  setValue() {
    this.form.setValue({first: 'Carson', last: 'Drew'});
  }
  patchValue(){
    this.form.patchValue({first: 'huanggou' })
  }
  getValue(){
    console.log(this.form.getRawValue(), this.form.value);
  }
  reset(){
    this.form.reset();
  }
}

test-group.component.html

<div>
  测试group:
<form [formGroup]="form" (ngSubmit)="onSubmit()">
  <div *ngIf="first?.invalid"> Name is too short. </div>
  <div *ngIf="first.errors?.checkName">UserName is exist! </div>
  <input formControlName="first" placeholder="First name">
  <input formControlName="last" placeholder="Last name">
  <button type="submit">Submit</button>
</form>

<button (click)="setValue()">Set preset value</button>
<button (click)="patchValue()">patchValue</button>
<button (click)="reset()">Set reset value</button>
<button (click)="getValue()">getvalue</button>
</div>

注意点:

  • 在模板中通过[formGroup]="form"指令,管理一个表单组。使用formControlName="name"控制表单元素,只能用在formGroup指令内部。

  • form.get('last')获取FormControl实例。

  • getRawValue()包括所有已禁用的控件。用value属性获取组中的值时,会从FormGroup中排除所有已禁用的控件。

  • setValue()必须传入全部的属性,缺少任意一个属性控制台会报错。patchValue()修改部分属性的值。

3、FormArray

test-array.component.ts

import { Component, forwardRef, OnInit } from '@angular/core';
import { FormArray, FormBuilder, FormControl, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';

@Component({
  selector: 'app-test-array',
  templateUrl: './test-array.component.html',
  styleUrls: ['./test-array.component.css'],
  providers: [{
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => TestArrayComponent),
    multi: true,
  }]
})
export class TestArrayComponent{
  address: FormArray;
  info: FormGroup;

  constructor(private fb: FormBuilder) { 
    this.address = this.fb.array([]);
    
    this.info = this.fb.group({
      address: this.address
    });
  }
  //添加地址
  addAddress() {
    this.address.push(new FormGroup({
      provience: new FormControl(),
      city: new FormControl()
    }));
  }

  //移除地址
  removeAddress(index) {
    this.address.removeAt(index);
  }

  //获取表单值
  getInfo() {
    console.log(this.info.value);
  }
}

test-array.component.html

<div [formGroup]="info">
  <div>
    <div>Address</div>
    <div><button (click)="addAddress()">Add</button></div>

    <div *ngFor="let address of info.get('address').controls;let idx=index">
      <p>
        Provience:<input [formControl]="address.get('provience')">
        City:<input [formControl]="address.get('city')">
        <button (click)="removeAddress(idx)">Remove</button>
      </p>
    </div>
  </div>
</div>
<button (click)="getInfo()">Get Info</button>

group -> array -> group={provience,city}

4、FormBuilder

使用户指定的配置创建AbstractControl。它提供了一个语法糖,用来简化FormControl、FormGroup 或 FormArray 实例的创建过程。它会减少构建复杂表单时所需的样板代码的数量。

test-builder.component.ts

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-test-builder',
  templateUrl: './test-builder.component.html',
  styleUrls: ['./test-builder.component.css'],
})
export class TestBuilderComponent {
  control: FormControl;
  group: FormGroup;

  constructor(private fb: FormBuilder){
   
    this.control = fb.control({
      value: 'xx' , disabled: true
    })

    this.group = fb.group({
      username: ['jack', Validators.required],
      password: ['', Validators.required]
    })
  }
}

test-builder.component.html

<div>
  测试builder:
  <input [formControl]="control" placeholder="First">

  <div [formGroup]="group">
    <label>Name:</label>
    <input type="text" formControlName="username">
    <div [style.color]="'red'" *ngIf="group.get('username').invalid && (group.get('username').touched || group.get('username').dirty)">
      <p *ngIf="group.get('username').errors.required">UserName can not be empty!</p>
      <p *ngIf="group.get('username').errors.checkName">UserName is exist!</p>
    </div>
    <label>Password:</label>
    <input type="password" formControlName="password">
    <div [style.color]="'red'" *ngIf="group.get('password').invalid && (group.get('password').touched || group.get('password').dirty)">
      <p *ngIf="group.get('password').errors.required">password can not be empty!</p>
      <p *ngIf="group.get('password').errors.password">password is illegal!</p>
    </div>
  </div>
</div>