Angular Reactive Forms -- Model-Driven Forms响应式表单
Angular 4.x 中有兩種表單:
-
Template-Driven Forms - 模板驅(qū)動(dòng)式表單 (類似于 AngularJS 1.x 中的表單 )? 官方文檔:https://v2.angular.cn/docs/ts/latest/guide/forms.html
-
Reactive Forms (Model-Driven Forms) - 響應(yīng)式表單? 官方文檔: https://v2.angular.cn/docs/ts/latest/guide/reactive-forms.html
Template-Driven Forms vs Reactive Forms
Template-Driven Forms (模板驅(qū)動(dòng)表單) 的特點(diǎn)
-
使用方便
-
適用于簡單的場景
-
通過 [(ngModel)] 實(shí)現(xiàn)數(shù)據(jù)雙向綁定
-
最小化組件類的代碼
-
不易于單元測試
- 異步的,模板驅(qū)動(dòng)表單會(huì)委托指令來創(chuàng)建它們的表單控件。 為了消除“檢查完后又變化了”的錯(cuò)誤,這些指令需要消耗一個(gè)以上的變更檢測周期來構(gòu)建整個(gè)控件樹。 這意味著在從組件類中操縱任何控件之前,我們都必須先等待一個(gè)節(jié)拍。
Reactive Forms (響應(yīng)式表單) 的特點(diǎn)
-
比較靈活
-
適用于復(fù)雜的場景
-
簡化了HTML模板的代碼,把驗(yàn)證邏輯抽離到組件類中
-
方便的跟蹤表單控件值的變化
-
易于單元測試
- 同步的 ,使用響應(yīng)式表單,我們會(huì)在代碼中創(chuàng)建整個(gè)表單控件樹。 我們可以立即更新一個(gè)值或者深入到表單中的任意節(jié)點(diǎn),因?yàn)樗械目丶际冀K是可用的。
使用?reactive forms 表單前,我們必須在?@NgModule?中導(dǎo)入?@angular/forms?庫中的?ReactiveFormsModule:
import { ReactiveFormsModule } from '@angular/forms';@NgModule({imports: [...,ReactiveFormsModule],declarations: [...],bootstrap: [...] }) export class AppModule {}友情提示:若使用 reactive forms,則導(dǎo)入 ReactiveFormsModule;若使用 template-driven 表單,則導(dǎo)入 FormsModule。
FormControl 和 FormGroup
FormControl - 它是一個(gè)為單個(gè)表單控件提供支持的類,可用于跟蹤控件的值和驗(yàn)證狀態(tài),此外還提供了一系列公共API。
使用示例:
ngOnInit() {this.myControl = new FormControl('Semlinker'); }FormGroup - 包含是一組 FormControl 實(shí)例,可用于跟蹤 FormControl 組的值和驗(yàn)證狀態(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?實(shí)例,接下來我們來看一下如何使用:
<form novalidate [formGroup]="myGroup">Name: <input type="text" formControlName="name">Location: <input type="text" formControlName="location"> </form>注意事項(xiàng):Template-Driven Forms 中介紹的?ngModel?和?name=""?屬性,已經(jīng)被移除了。這是一件好事,讓我們的模板更簡潔。
上面示例中,我們必須使用?[formGroup]?綁定我們創(chuàng)建的?myGroup?對(duì)象,除此之外還要使用?formControlName?指令,綁定我們創(chuàng)建的?FormControl?控件。此時(shí)的表單結(jié)構(gòu)如下:
FormGroup -> 'myGroup'FormControl -> 'name'FormControl -> 'location'User interface
signup.interface.ts
export interface User {name: string;account: {email: string;confirm: string;} }與之對(duì)應(yīng)的表單結(jié)構(gòu)如下:
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è)置初始數(shù)據(jù),我們可以按照上述示例進(jìn)行設(shè)置。通常情況下,我們通過服務(wù)端提供的 API 接口來獲取表單的初始信息。
綁定FormGroup模型
<form novalidate [formGroup]="user"><label><span>Full name</span><inputtype="text"placeholder="Your full name"formControlName="name"></label><div formGroupName="account"><label><span>Email address</span><inputtype="email"placeholder="Your email address"formControlName="email"></label><label><span>Confirm address</span><inputtype="email"placeholder="Confirm your email address"formControlName="confirm"></label></div><button type="submit">Sign up</button> </form>現(xiàn)在?FormGroup?與?FormControl?對(duì)象與 DOM 結(jié)構(gòu)的關(guān)聯(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'當(dāng)使用模板驅(qū)動(dòng)的表單時(shí),為了獲取?f.value?表單的值,我們需要先執(zhí)行?#f="ngForm"?的操作。而對(duì)于使用響應(yīng)式的表單,我們可以通過以下方式,方便的獲取表單的值:
{{ user.value | json }} // { name: '', account: { email: '', confirm: '' }}Reactive submit
跟模板驅(qū)動(dòng)的表單一樣,我們可以通過?ngSubmit?輸出屬性,處理表單的提交邏輯:
<form novalidate (ngSubmit)="onSubmit(user)" [formGroup]="user">... </form>需要注意的是,我們使用?user?對(duì)象作為?onSubmit()?方法的參數(shù),這使得我們可以獲取表單對(duì)象的相關(guān)信息,具體處理邏輯如下:
export class SignupFormComponent {user: FormGroup;onSubmit({ value, valid }: { value: User, valid: boolean }) {console.log(value, valid);} }上面代碼中,我們使用?Object destructuring?(對(duì)象解構(gòu)) 的方式,從user?對(duì)象中獲取?value?和?valid?屬性的值。其中?value的值,就是?user.value?的值。在實(shí)際應(yīng)用中,我們是不需要傳遞?user?參數(shù)的:
export class SignupFormComponent {user: FormGroup;onSubmit() {console.log(this.user.value, this.user.valid);} }表單的數(shù)據(jù)綁定方式和提交邏輯已經(jīng)介紹完了,是該介紹表單實(shí)際應(yīng)用中,一個(gè)重要的環(huán)節(jié) — 表單驗(yàn)證。
Reactive error validation
接下來我們來為表單添加驗(yàn)證規(guī)則,首先我們需要從?@angular/forms?中導(dǎo)入?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)})}); }通過以上示例,我們可以看出,如果表單控制包含多種驗(yàn)證規(guī)則,可以使用數(shù)組聲明多種驗(yàn)證規(guī)則。若只包含一種驗(yàn)證規(guī)則,直接聲明就好。通過這種方式,我們就不需要在模板的輸入控件中添加?required?屬性。接下來我們來添加表單驗(yàn)證失敗時(shí),不允許進(jìn)行表單提交功能:
<form novalidate (ngSubmit)="onSubmit(user)" [formGroup]="user">...<button type="submit" [disabled]="user.invalid">Sign up</button> </form>那么問題來了,我們要如何獲取表單控件的驗(yàn)證信息?我們可以使用模板驅(qū)動(dòng)表單中介紹的方式,具體如下:
<form novalidate [formGroup]="user">{{ user.controls.name?.errors | json }} </form>友情提示:?.prop 稱為安全導(dǎo)航操作符,用于告訴 Angular prop 的值可能不存在。
此外我們也可以使用?FormGroup?對(duì)象提供的 API,來獲取表單控件驗(yàn)證的錯(cuò)誤信息:
<form novalidate [formGroup]="user">{{ user.get('name').errors | json }} </form>完整代碼:
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><divclass="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><divclass="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);} }功能是實(shí)現(xiàn)了,但創(chuàng)建?FormGroup?對(duì)象的方式有點(diǎn)繁瑣,Angular 團(tuán)隊(duì)也意識(shí)到這點(diǎn),因此為我們提供?FormBuilder?,來簡化上面的操作。
Simplifying with FormBuilder
首先我們需要從?@angular/forms?中導(dǎo)入?FormBuilder:
import { FormBuilder, FormGroup, Validators } from '@angular/forms';export class SignupFormComponent implements OnInit {user: FormGroup;constructor(private fb: FormBuilder) {}... }使用FormBuilder:
@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);} }?
轉(zhuǎn)自:https://segmentfault.com/a/1190000009041192
轉(zhuǎn)載于:https://www.cnblogs.com/xuepei/p/7922022.html
總結(jié)
以上是生活随笔為你收集整理的Angular Reactive Forms -- Model-Driven Forms响应式表单的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 机器学习实战 k-近邻算法 手写识别系统
- 下一篇: container-with-most-