Angular 4.x中表單Reactive Forms詳解
Angular 4.x 中有兩種表單:
- Template-Driven Forms - 模板驅(qū)動式表單 (類似于 Angular 1.x 中的表單 )
- Reactive Forms (Model-Driven Forms) - 響應式表單
Template-Driven Forms (模板驅(qū)動表單) ,我們之前的文章已經(jīng)介紹過了,了解詳細信息,請查看 - Angular 4.x Template-Driven Forms 。
Contents
- ngModule and reactive forms
- FormControl and FormGroup
- Implementing our FormGroup model
- Binding our FormGroup model
- Reactive submit
- Reactive error validation
- Simplifying with FormBuilder
Form base and interface
Form base
<form novalidate> <label> <span>Full name</span> <input type="text" name="name" placeholder="Your full name"> </label> <div> <label> <span>Email address</span> <input type="email" name="email" placeholder="Your email address"> </label> <label> <span>Confirm address</span> <input type="email" name="confirm" placeholder="Confirm your email address"> </label> </div> <button type="submit">Sign up</button> </form>
接下來我們要實現(xiàn)的功能如下:
- 綁定 name、email、confirm 輸入框的值
- 為所有輸入框添加表單驗證功能
- 顯示驗證異常信息
- 表單驗證失敗時,不允許進行表單提交
- 表單提交功能
User interface
// signup.interface.ts export interface User { name: string; account: { email: string; confirm: string; } }
ngModule and reactive forms
在我們繼續(xù)深入介紹 reactive forms 表單前,我們必須在 @NgModule 中導入 @angular/forms 庫中的 ReactiveFormsModule:
import { ReactiveFormsModule } from '@angular/forms'; @NgModule({ imports: [ ..., ReactiveFormsModule ], declarations: [...], bootstrap: [...] }) export class AppModule {}
友情提示:若使用 reactive forms,則導入 ReactiveFormsModule;若使用 template-driven 表單,則導入 FormsModule。
Reactive approach
我們將基于上面的定義的基礎表單,創(chuàng)建 SignupFormComponent :
signup-form.component.ts
import { Component } from '@angular/core'; @Component({ selector: 'signup-form', template: ` <form novalidate>...</form> ` }) export class SignupFormComponent { constructor() {} }
這是一個基礎的組件,在我們實現(xiàn)上述功能前,我們需要先介紹 FormControl、FormGroup、FormBuilder 的概念和使用。
FormControl and FormGroup
我們先來介紹一下 FormControl 和 FormGroup 的概念:
1、FormControl - 它是一個為單個表單控件提供支持的類,可用于跟蹤控件的值和驗證狀態(tài),此外還提供了一系列公共API。
使用示例:
ngOnInit() { this.myControl = new FormControl('Semlinker'); }
2、FormGroup - 包含是一組 FormControl 實例,可用于跟蹤 FormControl 組的值和驗證狀態(tài),此外也提供了一系列公共API。
使用示例:
ngOnInit() { this.myGroup = new FormGroup({ name: new FormControl('Semlinker'), location: new FormControl('China, CN') }); }
現(xiàn)在我們已經(jīng)創(chuàng)建了 FormControl 和 FormGroup 實例,接下來我們來看一下如何使用:
<form novalidate [formGroup]="myGroup"> Name: <input type="text" formControlName="name"> Location: <input type="text" formControlName="location"> </form>
注意事項:Template-Driven Forms 中介紹的 ngModel 和 name="" 屬性,已經(jīng)被移除了。這是一件好事,讓我們的模板更簡潔。
上面示例中,我們必須使用 [formGroup] 綁定我們創(chuàng)建的 myGroup 對象,除此之外還要使用 formControlName 指令,綁定我們創(chuàng)建的 FormControl 控件。
此時的表單結構如下:
FormGroup -> 'myGroup' FormControl -> 'name' FormControl -> 'location'
Implementing our FormGroup model
signup.interface.ts
export interface User { name: string; account: { email: string; confirm: string; } }
與之對應的表單結構如下:
FormGroup -> 'user' FormControl -> 'name' FormGroup -> 'account' FormControl -> 'email' FormControl -> 'confirm'
是的,我們可以創(chuàng)建嵌套的 FormGroup 集合!讓我們更新一下組件 (不包含初始數(shù)據(jù)):
import { Component, OnInit } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; @Component({...}) export class SignupFormComponent implements OnInit { user: FormGroup; ngOnInit() { this.user = new FormGroup({ name: new FormControl(''), account: new FormGroup({ email: new FormControl(''), confirm: new FormControl('') }) }); } }
如果我們想要設置初始數(shù)據(jù),我們可以按照上述示例進行設置。通常情況下,我們通過服務端提供的 API 接口來獲取表單的初始信息。
Binding our FormGroup model
現(xiàn)在我們已經(jīng)實例化了 FormGroup 模型,是時候綁定到對應的 DOM 元素上了。具體示例如下:
<form novalidate [formGroup]="user"> <label> <span>Full name</span> <input type="text" placeholder="Your full name" formControlName="name"> </label> <div formGroupName="account"> <label> <span>Email address</span> <input type="email" placeholder="Your email address" formControlName="email"> </label> <label> <span>Confirm address</span> <input type="email" placeholder="Confirm your email address" formControlName="confirm"> </label> </div> <button type="submit">Sign up</button> </form>
現(xiàn)在 FormGroup 與 FormControl 對象與 DOM 結構的關聯(lián)信息如下:
// JavaScript APIs FormGroup -> 'user' FormControl -> 'name' FormGroup -> 'account' FormControl -> 'email' FormControl -> 'confirm' // DOM bindings formGroup -> 'user' formControlName -> 'name' formGroupName -> 'account' formControlName -> 'email' formControlName -> 'confirm'
當使用模板驅(qū)動的表單時,為了獲取 f.value 表單的值,我們需要先執(zhí)行 #f="ngForm"
的操作。而對于使用響應式的表單,我們可以通過以下方式,方便的獲取表單的值:
{{ user.value | json }} // { name: '', account: { email: '', confirm: '' }}
Reactive submit
跟模板驅(qū)動的表單一樣,我們可以通過 ngSubmit 輸出屬性,處理表單的提交邏輯:
<form novalidate (ngSubmit)="onSubmit(user)" [formGroup]="user"> ... </form>
需要注意的是:我們使用 user 對象作為 onSubmit()
方法的參數(shù),這使得我們可以獲取表單對象的相關信息,具體處理邏輯如下:
export class SignupFormComponent { user: FormGroup; onSubmit({ value, valid }: { value: User, valid: boolean }) { console.log(value, valid); } }
上面代碼中,我們使用 Object destructuring (對象解構) 的方式,從user 對象中獲取 value 和 valid 屬性的值。其中 value 的值,就是 user.value 的值。在實際應用中,我們是不需要傳遞 user 參數(shù)的:
export class SignupFormComponent { user: FormGroup; onSubmit() { console.log(this.user.value, this.user.valid); } }
表單的數(shù)據(jù)綁定方式和提交邏輯已經(jīng)介紹完了,是該介紹表單實際應用中,一個重要的環(huán)節(jié) — 表單驗證。
Reactive error validation
接下來我們來為表單添加驗證規(guī)則,首先我們需要從 @angular/forms 中導入 Validators。具體使用示例如下:
ngOnInit() { this.user = new FormGroup({ name: new FormControl('', [Validators.required, Validators.minLength(2)]), account: new FormGroup({ email: new FormControl('', Validators.required), confirm: new FormControl('', Validators.required) }) }); }
通過以上示例,我們可以看出,如果表單控制包含多種驗證規(guī)則,可以使用數(shù)組聲明多種驗證規(guī)則。若只包含一種驗證規(guī)則,直接聲明就好。通過這種方式,我們就不需要在模板的輸入控件中添加 required 屬性。接下來我們來添加表單驗證失敗時,不允許進行表單提交功能:
<form novalidate (ngSubmit)="onSubmit(user)" [formGroup]="user"> ... <button type="submit" [disabled]="user.invalid">Sign up</button> </form>
那么問題來了,我們要如何獲取表單控件的驗證信息?我們可以使用模板驅(qū)動表單中介紹的方式,具體如下:
<form novalidate [formGroup]="user"> {{ user.controls.name?.errors | json }} </form>
友情提示: ?.prop 稱為安全導航操作符,用于告訴 Angular prop 的值可能不存在。
此外我們也可以使用 FormGroup 對象提供的 API,來獲取表單控件驗證的錯誤信息:
<form novalidate [formGroup]="user"> {{ user.get('name').errors | json }} </form>
現(xiàn)在我們來看一下完整的代碼:
import { Component, OnInit } from '@angular/core'; import { FormControl, FormGroup, Validators } from '@angular/forms'; import { User } from './signup.interface'; @Component({ selector: 'signup-form', template: ` <form novalidate (ngSubmit)="onSubmit(user)" [formGroup]="user"> <label> <span>Full name</span> <input type="text" placeholder="Your full name" formControlName="name"> </label> <div class="error" *ngIf="user.get('name').hasError('required') && user.get('name').touched"> Name is required </div> <div class="error" *ngIf="user.get('name').hasError('minlength') && user.get('name').touched"> Minimum of 2 characters </div> <div formGroupName="account"> <label> <span>Email address</span> <input type="email" placeholder="Your email address" formControlName="email"> </label> <div class="error" *ngIf="user.get('account').get('email').hasError('required') && user.get('account').get('email').touched"> Email is required </div> <label> <span>Confirm address</span> <input type="email" placeholder="Confirm your email address" formControlName="confirm"> </label> <div class="error" *ngIf="user.get('account').get('confirm').hasError('required') && user.get('account').get('confirm').touched"> Confirming email is required </div> </div> <button type="submit" [disabled]="user.invalid">Sign up</button> </form> ` }) export class SignupFormComponent implements OnInit { user: FormGroup; constructor() {} ngOnInit() { this.user = new FormGroup({ name: new FormControl('', [Validators.required, Validators.minLength(2)]), account: new FormGroup({ email: new FormControl('', Validators.required), confirm: new FormControl('', Validators.required) }) }); } onSubmit({ value, valid }: { value: User, valid: boolean }) { console.log(value, valid); } }
功能是實現(xiàn)了,但創(chuàng)建 FormGroup 對象的方式有點繁瑣,Angular 團隊也意識到這點,因此為我們提供 FormBuilder ,來簡化上面的操作。
Simplifying with FormBuilder
首先我們需要從 @angular/forms 中導入 FormBuilder:
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; export class SignupFormComponent implements OnInit { user: FormGroup; constructor(private fb: FormBuilder) {} ... }
然后我們使用 FormBuilder 對象提供的 group() 方法,來創(chuàng)建 FormGroup 和 FormControl 對象:
調(diào)整前的代碼 (未使用FormBuilder):
ngOnInit() { this.user = new FormGroup({ name: new FormControl('', [Validators.required, Validators.minLength(2)]), account: new FormGroup({ email: new FormControl('', Validators.required), confirm: new FormControl('', Validators.required) }) }); }
調(diào)整后的代碼 (使用FormBuilder):
ngOnInit() { this.user = this.fb.group({ name: ['', [Validators.required, Validators.minLength(2)]], account: this.fb.group({ email: ['', Validators.required], confirm: ['', Validators.required] }) }); }
對比一下調(diào)整前和調(diào)整后的代碼,是不是感覺一下子方便了許多。此時更新完后完整的代碼如下:
@Component({...}) export class SignupFormComponent implements OnInit { user: FormGroup; constructor(private fb: FormBuilder) {} ngOnInit() { this.user = this.fb.group({ name: ['', [Validators.required, Validators.minLength(2)]], account: this.fb.group({ email: ['', Validators.required], confirm: ['', Validators.required] }) }); } onSubmit({ value, valid }: { value: User, valid: boolean }) { console.log(value, valid); } }
我有話說
Template-Driven Forms vs Reactive Forms
Template-Driven Forms (模板驅(qū)動表單) 的特點
- 使用方便
- 適用于簡單的場景
- 通過 [(ngModel)] 實現(xiàn)數(shù)據(jù)雙向綁定
- 最小化組件類的代碼
- 不易于單元測試
Reactive Forms (響應式表單) 的特點
- 比較靈活
- 適用于復雜的場景
- 簡化了HTML模板的代碼,把驗證邏輯抽離到組件類中
- 方便的跟蹤表單控件值的變化
- 易于單元測試
總結
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關文章
解決Angular2 router.navigate刷新頁面的問題
今天小編就為大家分享一篇解決Angular2 router.navigate刷新頁面的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08AngularJS實現(xiàn)根據(jù)變量改變動態(tài)加載模板的方法
這篇文章主要介紹了AngularJS實現(xiàn)根據(jù)變量改變動態(tài)加載模板的方法,結合實例形式簡單分析了AngularJS動態(tài)加載模板的主要操作技巧與模板實現(xiàn)代碼,需要的朋友可以參考下2016-11-11AngularJS框架的ng-app指令與自動加載實現(xiàn)方法分析
這篇文章主要介紹了AngularJS框架的ng-app指令與自動加載實現(xiàn)方法,結合實例形式分析了ng-app指令的功能及自動加載機制的實現(xiàn)技巧,需要的朋友可以參考下2017-01-01詳解AngularJS controller調(diào)用factory
本篇文章主要介紹了詳解AngularJS controller調(diào)用factory,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-05-05詳解Angular數(shù)據(jù)綁定及其實現(xiàn)方式
數(shù)據(jù)綁定是將應用程序UI或用戶界面綁定到模型的機制。使用數(shù)據(jù)綁定,用戶將能夠使用瀏覽器來操縱網(wǎng)站上存在的元素。2021-05-05