[Angular] Forms - Reactive Forms

前言

Reactive forms提供了一种model-driven的方法来处理表单中会随时间变化的输入(数据),本篇中介绍着如何控制与更新一个表单、使用多个form-group、表单验证等等的基本表单操作。


Overview of reactive forms

Reactive forms使用了显式且不变的方法管理表单状况,对于表单的状态的更改每次都会回传一个新的表单状态,由于每次都会回传一个新的状态,所以他可以保持每次该改之间的model完整性,Reactive forms是围绕着observable所建立的,表单中的输入(数值)会提供给input flow作为他的值并可以以同步的方式访问。

Reactive forms与template forms不同,Reactive forms通过对数据模型的同步访问提供了较高的可预测性observable operators的不变性可以透过observable streams观察数据的变更

Adding a basic form control

建立Reactive forms的三个步骤:

在你的app中注册reactive foms module,这个module中含有使用Reactive forms的指令。在Component中新增一个新的FormControl instance。在templete中注册FormControl。

Register the reactive forms module

使用import关键字将ReactiveFormsModule添加到app.module中的import阵列中。

// src/app/app.module.ts import { ReactiveFormsModule } from '@angular/forms';@NgModule({  imports: [    // other imports ...    ReactiveFormsModule  ],})export class AppModule { }

接下来透过cli建立一个 name-editor Component,并将FormControlclass加入到Component中并将他实体化。

// src/app/name-editor/name-editor.component.tsimport { Component } from '@angular/core';import { FormControl } from '@angular/forms'; // import FormControl Class@Component({  selector: 'app-name-editor',  templateUrl: './name-editor.component.html',  styleUrls: ['./name-editor.component.css']})export class NameEditorComponent {  name = new FormControl(''); // instance FormControl class}

Register the control in the template

name-editor的templete中建立可以与表单控制元件连动的网页元件,使用formControl绑定templete中的元件。

<!-- src/app/name-editor/name-editor.component.html --><label>  Name:  <input type="text" [formControl]="name"></label>

在画面中显示出来

<!-- src/app/app.component.html  --><app-name-editor></app-name-editor>

Displaying a form control value

可以透过两种方法显示forms中的数值:

可以透过valueChange()中的subscription()方法监听表单中的值。使用FormControl中的value属性。
name = new FormControl('');this.name.valueChanges.subscribe(val => console.log(val));
Value : {{name.value}}

Grouping form controls

一个表单中会包含几个相关的控制元件,Reactive forms提供两种方法可以将多个相关的控制组件分组为单个输入形式

使用form group定义一组固定的控制组件表单,可以统一管理这些类似的表单组件。使用form array定义一个动态的表单,可以随时添加或删除控制组件。

透过cli建立一个新组建,使用import将FormGroupFormControl加入Component中并将他们实例化。

// src/app/profile-editor/profile-editor.component.ts (form group)import { Component } from '@angular/core';import { FormGroup, FormControl } from '@angular/forms'; //import two class@Component({  selector: 'app-profile-editor',  templateUrl: './profile-editor.component.html',  styleUrls: ['./profile-editor.component.css']})export class ProfileEditorComponent {  // instance FormGroup & FormControl  profileForm = new FormGroup({    firstName: new FormControl(''),    lastName: new FormControl(''),  });}

firstNamelastName这两个相关的控制组件透过FormGroup分组为一个群组。

Create a nested groups

可以透过嵌套FromGroups来达到将较为複杂的表单内容分割为更小的Group,以方便管理以维护。

import { Component } from '@angular/core';import { FormGroup, FormControl } from '@angular/forms';@Component({  selector: 'app-profile-editor',  templateUrl: './profile-editor.component.html',  styleUrls: ['./profile-editor.component.css']})export class ProfileEditorComponent {  profileForm = new FormGroup({    firstName: new FormControl(''),    lastName: new FormControl(''),    address: new FormGroup({      street: new FormControl(''),      city: new FormControl(''),      state: new FormControl(''),      zip: new FormControl('')    })  });}

将原本的profileForm Group中新增了第二层的嵌套Group,将street、city、state、zip绑定为一个FormGroup,透过这样的绑定可以将原本的profileForm保持完整的前提下再新增出一个Group。

<form [formGroup]="profileForm">  <label>    First Name:    <input type="text" formControlName="firstName">  </label>  <label>    Last Name:    <input type="text" formControlName="lastName">  </label>    <div formGroupName="address">      <h3>Address</h3>      <label>        Street:        <input type="text" formControlName="street">      </label>      <label>        City:        <input type="text" formControlName="city">      </label>      <label>        State:        <input type="text" formControlName="state">      </label>      <label>        Zip Code:        <input type="text" formControlName="zip">      </label>  </div>  <button type="submit" [disabled]="!profileForm.valid">Submit</button></form>

Updating parts of the data model

当需要更新多个控制组件的值时,Angular提供两种方法可以改变值,一种是可以更改整组表单的方法,另一种是更改表单部分内容的方法。

使用setValue()可以更新整个表单内容,他必须要遵守整个表单的结构。使用patchValue()可以替换表单内的部分内容。

使用setValue()会严格检查整个表单的结构,若结构错误则会发生嵌套错误,若是使用patchValue()在这个错误上会默默地失败。

updateProfile() {  this.profileForm.patchValue({    firstName: 'Nancy',    address: {      street: '123 Drew Street'    }  });}

Using the FormBuilder service to generate controls

对于在处理多个表单的时候还是使用手动的方式创建表单控制组件实例,这样的话可能会遇到重複宣告的问题,所以可以使用FormBuilder,它提供了用于生成控制组件的便利方法。

import FormBuilder Class.Inject the FormBuilder service.Generate the form contents.

Import the FormBuilder class

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

Inject the FormBuilder service

在Component的comstructor中Inject FormBuilder service

constructor(private fb: FormBuilder) { }

Generate form controls

FormBuilder提供control()group()array()这三个方法,他们用于生成实例包括FormControl、FormGroup、FromArray。

import { Component } from '@angular/core';import { FormBuilder } from '@angular/forms';@Component({  selector: 'app-profile-editor',  templateUrl: './profile-editor.component.html',  styleUrls: ['./profile-editor.component.css']})export class ProfileEditorComponent {  profileForm = this.fb.group({    firstName: [''],    lastName: [''],    address: this.fb.group({      street: [''],      city: [''],      state: [''],      zip: ['']    }),  });  constructor(private fb: FormBuilder) { }}

Creating dynamic forms

FormArray是用于管理任何数量的未命名控件的FormGroup的替代方法,可以动态的插入或删除,所以不知道子值的数量时可以使用FormArray来代替FormGroup。

Import the FormArray class.Define a FormArray control.使用get()访问FormArray control.Display the form array in a template.

Import the FormArray class

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

Define a FormArray control

通过在数组中定义控件,可以使用从零到许多的任意数量的控件来初始化表单数组,使用FormBuilder.array()定义阵列并使用FormBuilder.control()初始化控件填充数组。

profileForm = this.fb.group({  firstName: ['', Validators.required],  lastName: [''],  address: this.fb.group({    street: [''],    city: [''],    state: [''],    zip: ['']  }),  aliases: this.fb.array([    this.fb.control('')  ])});

Access the FormArray control

可以使用getter可以轻鬆访问表单阵列的实例的别名。

get aliases() {  return this.profileForm.get('aliases') as FormArray;}

还可以使用FormArray.push()将表单数据动态的插入到现有表单中。

addAlias() {  this.aliases.push(this.fb.control(''));}

Display the form array in the template

<div formArrayName="aliases">  <h3>Aliases</h3> <button (click)="addAlias()">Add Alias</button>  <div *ngFor="let alias of aliases.controls; let i=index">    <!-- The repeated alias template -->    <label>      Alias:      <input type="text" [formControlName]="i">    </label>  </div></div>

使用*ngFor遍历aliases中的所有表单实例,因为表单数组元素未命名,所以您将索引分配给i变量,并将其传递给每个控件以将其绑定到formControlName输入。


Reactive forms API summary

Classes

ClassDescriptionAbstractControlFormControl,FormGroup和FormArray的抽象基类,它提供了常见的行为和属性。FormControl管理单个表单空间的值和有效性的状态,他对应到HTML的表单控件<input><select>FormGroup管理一组AbstractControl实例的值和有效状态,它包含他这个FormGroup的子FormControl。FormArray管理AbstractControl实例的阵列的值有效性。FormBuilder用于创建FormControl的方法。

Directives

DirectiveDescriptionFormControlDirective将独立的FormControl实例同步到表单控件元素。FormControlName通过名称将现有FormGroup实例中的FormControl同步到表单控件元素。FormGroupDirective将现有的FormGroup实例同步到DOM元素。FormGroupName将嵌套的FormGroup实例同步到DOM元素。FormArrayName将嵌套的FormArray实例同步到DOM元素。

参考文献:
Angular - Reactive Forms


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章