欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

ng-book札记——表单

程序员文章站 2022-05-07 21:18:17
Angular表单的基本对象为FormControl与FormGroup。 FormControl FormControl代表单个input表单字段(field),即Angular表单的最小单元。 FormControl封装了表单字段的值与状态(valid, dirty, errors)。 在Typ ......

Angular表单的基本对象为FormControl与FormGroup。

FormControl

FormControl代表单个input表单字段(field),即Angular表单的最小单元。
FormControl封装了表单字段的值与状态(valid, dirty, errors)。

在TypeScript中创建FormControl:

// create a new FormControl with the value "Nate"
let nameControl = new FormControl("Nate");

let name = nameControl.value; // -> Nate

// now we can query this control for certain values:
nameControl.errors // -> StringMap<string, any> of errors
nameControl.dirty // -> false
nameControl.valid // -> true

在DOM中绑定:

<input type="text" [formControl]="nameControl" />

FormGroup

FormGroup是FormControl集合的包装器。

let personInfo = new FormGroup({
  firstName: new FormControl("Nate"),
  lastName: new FormControl("Murray"),
  zip: new FormControl("90210")
})

由于FormGroup与FormControl继承了相同的基类(AbstractControl),这意味着可以像FormControl一样检查其值与状态。

personInfo.value; // -> {
// firstName: "Nate",
// lastName: "Murray",
// zip: "90210"
// }

// now we can query this control group for certain values, which have sensible
// values depending on the children FormControl's values:
personInfo.errors // -> StringMap<string, any> of errors
personInfo.dirty // -> false
personInfo.valid // -> true

Angular中使用表单有FormsModule与ReactiveFormsModule两种方式。

FormsModule

导入FormsModule后, 将自动对相关视图中的任意<form>标签附加NgForm。
NgForm提供两样功能:

  1. 名为ngForm的FormGroup
  2. (ngSubmit)
import {
  FormsModule
} from '@angular/forms';

// farther down...

@NgModule({
  declarations: [
    FormsDemoApp,
    DemoFormSkuComponent,
    // ... our declarations here
  ],
  imports: [
    BrowserModule,
    FormsModule, // <-- add this
  ],
  bootstrap: [ FormsDemoApp ]
})
class FormsDemoAppModule {}
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-demo-form-sku',
  templateUrl: './demo-form-sku.component.html',
  styles: []
})
export class DemoFormSkuComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

  onSubmit(form: any): void {
    console.log('you submitted value:', form);
  }
}
<div class="ui raised segment">
  <h2 class="ui header">Demo Form: Sku</h2>
  <form #f="ngForm"
    (ngSubmit)="onSubmit(f.value)"
    class="ui form">

  <div class="field">
    <label for="skuInput">SKU</label>
    <input type="text"
      id="skuInput"
      placeholder="SKU"
      name="sku" ngModel>
  </div>

  <button type="submit" class="ui button">Submit</button>
  </form>
</div>

#f="ngForm"为视图创建一个本地变量f,并绑定了ngForm。这样在视图的其它地方就可以灵活使用,比如在(ngSubmit)="onSubmit(f.value)中。

在input元素里,单独的ngModel特性表示一个单向绑定,以及在表单中创建一个名为sku的FormControl,并且自动添加至父级的FormGroup(这里是form)。

ReactiveFormsModule

这种方式下可以通过FormBuilder帮助创建FormGroup与FormControl。

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

// farther down...

@NgModule({
  declarations: [
    FormsDemoApp,
    DemoFormSkuComponent,
    // ... our declarations here
  ],
  imports: [
    BrowserModule,
    ReactiveFormsModule // <-- and this
  ],
  bootstrap: [ FormsDemoApp ]
})
class FormsDemoAppModule {}
import { Component, OnInit } from '@angular/core';
import {
  FormBuilder,
  FormGroup
} from '@angular/forms';

@Component({
  selector: 'app-demo-form-sku-with-builder',
  templateUrl: './demo-form-sku-with-builder.component.html',
  styles: []
})
export class DemoFormSkuWithBuilderComponent implements OnInit {
  myForm: FormGroup;

  constructor(fb: FormBuilder) {
    this.myForm = fb.group({
    'sku': ['ABC123']
    });
  }

  ngOnInit() {
  }

  onSubmit(value: string): void {
    console.log('you submitted value: ', value);
  }
}
<div class="ui raised segment">
  <h2 class="ui header">Demo Form: Sku with Builder</h2>
  <form [formGroup]="myForm"
    (ngSubmit)="onSubmit(myForm.value)"
    class="ui form">

  <div class="field">
    <label for="skuInput">SKU</label>
    <input type="text"
      id="skuInput"
      placeholder="SKU"
      [formControl]="myForm.controls['sku']">
  </div>

  <button type="submit" class="ui button">Submit</button>
  </form>
</div>

视图中通过[formGroup]="myForm"绑定已创建的FormGroup,同时onSubmit也改为myForm.value。
而对于input元素,现在借由[formControl]="myForm.controls['sku']"方式绑定已创建的FormControl。

验证

向一个FormControl添加验证器很简单,只需要将其传入第二个参数。

let control = new FormControl('sku', Validators.required);

如果是FormBuilder的话,可以使用以下语法:

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

@Component({
  selector: 'app-demo-form-with-validations-explicit',
  templateUrl: './demo-form-with-validations-explicit.component.html',
  styles: []
})
export class DemoFormWithValidationsExplicitComponent {
  myForm: FormGroup;
  sku: AbstractControl;

  constructor(fb: FormBuilder) {
    this.myForm = fb.group({
    'sku': ['', Validators.required]
  });

    this.sku = this.myForm.controls['sku'];
  }

  onSubmit(value: string): void {
    console.log('you submitted value: ', value);
  }
}
<div class="ui raised segment">
<h2 class="ui header">Demo Form: with validations (explicit)</h2>
<form [formGroup]="myForm"
  (ngSubmit)="onSubmit(myForm.value)"
  class="ui form"
  [class.error]="!myForm.valid && myForm.touched">

    <div class="field"
      [class.error]="!sku.valid && sku.touched">
      <label for="skuInput">SKU</label>
      <input type="text"
        id="skuInput"
        placeholder="SKU"
        [formControl]="sku">
      <div *ngIf="!sku.valid"
        class="ui error message">SKU is invalid</div>
      <div *ngIf="sku.hasError('required')"
        class="ui error message">SKU is required</div>
    </div>

    <div *ngIf="!myForm.valid"
      class="ui error message">Form is invalid</div>

    <button type="submit" class="ui button">Submit</button>
  </form>
</div>

* 通过myForm的valid属性值可以判断所有FormControl是否皆有效。
* [class.error]可以根据FormControl有效与否变更样式。
* sku.hasError('required'),可以指定特定的验证要求。

验证器还能够按照需求定制:

function skuValidator(control: FormControl): { [s: string]: boolean } {
  if (!control.value.match(/^123/)) {
    return {invalidSku: true};
  }
}

constructor(fb: FormBuilder) {
  this.myForm = fb.group({
    'sku': ['', Validators.compose([
    Validators.required, skuValidator])]
  });
<div *ngIf="sku.hasError('invalidSku')"
  class="ui error message">SKU must begin with <span>123</span></div>

监察

FormGroup与FormControl都有自己的EventEmitter,可以用于观察变化。
方式很简单,使用其valueChanges的subscribe方法进行订阅。

constructor(fb: FormBuilder) {
  this.myForm = fb.group({
    'sku': ['', Validators.required]
  });

  this.sku = this.myForm.controls['sku'];

  this.sku.valueChanges.subscribe(
    (value: string) => {
      console.log('sku changed to:', value);
    }
  );

  this.myForm.valueChanges.subscribe(
    (form: any) => {
      console.log('form changed to:', form);
    }
  );
}