本篇內(nèi)容主要講解“angular中表單的響應(yīng)式和模板驅(qū)動怎么實現(xiàn)”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“angular中表單的響應(yīng)式和模板驅(qū)動怎么實現(xiàn)”吧!
10年積累的成都網(wǎng)站制作、網(wǎng)站建設(shè)經(jīng)驗,可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認識你,你也不認識我。但先網(wǎng)站制作后付款的網(wǎng)站建設(shè)流程,更有廣平免費網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
Angular 提供了兩種不同的方法來通過表單處理用戶輸入:響應(yīng)式表單
和模板驅(qū)動表單
。 兩者都從視圖中捕獲用戶輸入事件、驗證用戶輸入、創(chuàng)建表單模型、修改數(shù)據(jù)模型,并提供跟蹤這些更改的途徑。
響應(yīng)式表單
提供對底層表單對象模型直接
、顯式
的訪問。它們與模板驅(qū)動表單相比,更加健壯:它們的可擴展性、可復(fù)用性和可測試性
都更高。如果表單是你的應(yīng)用程序的關(guān)鍵部分,或者你已經(jīng)在使用響應(yīng)式表單來構(gòu)建應(yīng)用,那就使用響應(yīng)式表單。
模板驅(qū)動表單
依賴模板中的指令
來創(chuàng)建和操作底層的對象模型。它們對于向應(yīng)用添加一個簡單的表單非常有用,比如電子郵件列表注冊表單。它們很容易添加到應(yīng)用中,但在擴展性方面不如響應(yīng)式表單。如果你有可以只在模板中管理的非?;镜谋韱涡枨蠛瓦壿?,那么模板驅(qū)動表單就很合適。
響應(yīng)式 | 模板驅(qū)動 | |
---|---|---|
建立表單模型 | 顯式的,在組件類中創(chuàng)建 | 隱式的,由指令創(chuàng)建 |
數(shù)據(jù)模型 | 結(jié)構(gòu)化和不可變的 | 非結(jié)構(gòu)化和可變的 |
可預(yù)測性 | 同步 | 異步 |
表單驗證 | 函數(shù) | 指令 |
響應(yīng)式表單和模板驅(qū)動型表單都會跟蹤用戶與之交互的表單輸入元素和組件模型中的表單數(shù)據(jù)之間的值變更。這兩種方法共享同一套底層構(gòu)建塊
,只在如何創(chuàng)建
和管理
常用表單控件實例
方面有所不同。
響應(yīng)式表單和模板驅(qū)動表單都建立在下列基礎(chǔ)類之上。
FormControl 實例用于追蹤單個表單控件的值和驗證狀態(tài)。
FormGroup 用于追蹤一個表單控件組的值和狀態(tài)。
FormArray 用于追蹤表單控件數(shù)組的值和狀態(tài)。
ControlValueAccessor 用于在 Angular 的 FormControl 實例和原生 DOM 元素之間創(chuàng)建一個橋梁。
響應(yīng)式表單使用顯式的、不可變的方式,管理表單在特定的時間點上的狀態(tài)。對表單狀態(tài)的每一次變更都會返回一個新的狀態(tài),這樣可以在變化時維護模型的整體性。響應(yīng)式表單是圍繞 Observable
流構(gòu)建的,表單的輸入和值都是通過這些輸入值組成的流來提供的,它可以同步
訪問。
使用表單控件有三個步驟。
在你的應(yīng)用中注冊響應(yīng)式表單模塊。該模塊聲明了一些你要用在響應(yīng)式表單中的指令。
生成一個新的 FormControl 實例,并把它保存在組件中。
在模板中注冊這個 FormControl。
要使用響應(yīng)式表單控件,就要從 @angular/forms 包中導(dǎo)入 ReactiveFormsModule,并把它添加到你的 NgModule 的 imports 數(shù)組中。
import { ReactiveFormsModule } from '@angular/forms'; @NgModule({ imports: [ // other imports ... ReactiveFormsModule ], }) export class AppModule { }
要注冊一個表單控件,就要導(dǎo)入 FormControl 類并創(chuàng)建一個 FormControl 的新實例,將其保存為類的屬性。
import { Component } from '@angular/core'; import { FormControl } from '@angular/forms'; @Component({ selector: 'app-name-editor', templateUrl: './name-editor.component.html', styleUrls: ['./name-editor.component.css'] }) export class NameEditorComponent { name = new FormControl(''); }
可以用 FormControl 的構(gòu)造函數(shù)設(shè)置初始值
,這個例子中它是空字符串
。通過在你的組件類中創(chuàng)建這些控件,你可以直接對表單控件的狀態(tài)進行監(jiān)聽
、修改
和校驗
。
在組件類中創(chuàng)建了控件之后,你還要把它和模板中的一個表單控件關(guān)聯(lián)起來。修改模板,為表單控件添加 formControl 綁定,formControl 是由 ReactiveFormsModule 中的 FormControlDirective 提供的。
你可以用下列方式顯示它的值:
通過可觀察對象 valueChanges
,你可以在模板中使用 AsyncPipe
或在組件類中使用 subscribe()
方法來監(jiān)聽表單值的變化。
使用 value 屬性。它能讓你獲得當(dāng)前值的一份快照。
Value: {{ name.value }}
public name = new FormControl('test'); public testValueChange() { this.name.valueChanges.subscribe({ next: value => { console.log("name value is: " + value); } }) }
響應(yīng)式表單還有一些方法可以用編程的方式``修改
控件的值,它讓你可以靈活的修改控件的值而不需要借助用戶交互。FormControl 提供了一個 setValue()
方法,它會修改這個表單控件的值,并且驗證與控件結(jié)構(gòu)相對應(yīng)的值的結(jié)構(gòu)。比如,當(dāng)從后端 API 或服務(wù)接收到了表單數(shù)據(jù)時,可以通過 setValue() 方法來把原來的值替換為新的值。
updateName() { this.name.setValue('Nancy' + new Date().getTime()); }
表單中通常會包含幾個相互關(guān)聯(lián)的控件
。響應(yīng)式表單提供了兩種把多個相關(guān)控件分組到同一個輸入表單中的方法。
表單組
定義了一個帶有一組控件的表單,你可以把它們放在一起管理。表單組的基礎(chǔ)知識將在本節(jié)中討論。你也可以通過嵌套表單組
來創(chuàng)建更復(fù)雜的表單。
表單數(shù)組
定義了一個動態(tài)表單,你可以在運行時添加和刪除控件。你也可以通過嵌套表單數(shù)組
來創(chuàng)建更復(fù)雜的表單
要將表單組添加到此組件中,請執(zhí)行以下步驟。
創(chuàng)建一個 FormGroup
實例。
把這個 FormGroup 模型關(guān)聯(lián)到視圖。
保存表單數(shù)據(jù)。
在組件類中創(chuàng)建一個名叫 profileForm 的屬性,并設(shè)置為 FormGroup 的一個新實例。要初始化這個 FormGroup,請為構(gòu)造函數(shù)提供一個由控件組成的對象,對象中的每個名字都要和表單控件的名字一一對應(yīng)。
import { FormControl, FormGroup } from '@angular/forms'; profileForm = new FormGroup({ firstName: new FormControl(''), lastName: new FormControl(''), }); // 可以整個獲取值 public onSubmit() { // TODO: Use EventEmitter with form value console.warn(this.profileForm.value);// {firstName: "", lastName: ""} } // 可以借助 valueChanges 整個可觀察對象整個獲取值 this.profileForm.valueChanges.subscribe( { next: value => { console.log("name value is: " + JSON.stringify(value)); // dashboard.component.ts:53 name value is: {"firstName":"dddd","lastName":"bb"} } }) // 可以通過后期單個控件單獨獲取值 this.profileForm.get('firstName').valueChanges.subscribe({ next: value => { console.log("First Name is: " + value); // First Name is: aa }
ps: 這個 FormGroup 用對象的形式提供了它的模型值,這個值來自組中每個控件的值
。 FormGroup 實例擁有和 FormControl 實例相同的屬性
(比如 value、untouched)和方法(比如 setValue())。
這個表單組還能跟蹤其中每個控件的狀態(tài)及其變化,所以如果其中的某個控件的狀態(tài)或值變化了,父控件也會發(fā)出一次新的狀態(tài)變更或值變更事件。該控件組的模型來自它的所有成員。在定義了這個模型之后,你必須更新模板,來把該模型反映到視圖中。
表單組可以同時接受單個表單控件實例和其它表單組實例作為其子控件。這可以讓復(fù)雜的表單模型更容易維護,并在邏輯上把它們分組到一起。
要制作更復(fù)雜的表單,請遵循如下步驟。
創(chuàng)建一個嵌套的表單組
板中對這個嵌套表單分組。
要在 profileForm 中創(chuàng)建一個嵌套組,就要把一個嵌套的 address 元素添加到此表單組的實例中。
public profileForm = new FormGroup({ firstName: new FormControl(''), lastName: new FormControl(''), address: new FormGroup({ street: new FormControl(''), city: new FormControl(''), state: new FormControl(''), zip: new FormControl('') }) }); // 可以借助 valueChanges 整個可觀察對象整個獲取值 this.profileForm.valueChanges.subscribe( { next: value => { console.log("name value is: " + JSON.stringify(value));// name value is: {"firstName":"","lastName":"","address":{"street":"b","city":"","state":"","zip":""}} } }); // 可以通過后期單個控件單獨獲取值 this.profileForm.get('firstName').valueChanges.subscribe({ next: value => { console.log("First Name is: " + value); } }); // 可以獲取form組件某個form組的整個值 this.profileForm.get('address').valueChanges.subscribe(({ next: value => { console.log('address value is: ' + JSON.stringify(value));// address value is: {"street":"b","city":"","state":"","zip":""} } })); // 可以獲取form組件某個form組的某個formcontrol實例的值 this.profileForm.get('address').get('street').valueChanges.subscribe(({ next: value => { console.log('street value is: ' + value);// street value is: b } }));
在修改了組件類中的模型之后,還要修改模板,來把這個 FormGroup 實例對接到它的輸入元素。
當(dāng)修改包含多個 FormGroup 實例的值時,你可能只希望更新模型中的一部分,而不是完全替換掉。
有兩種更新模型值的方式:
使用 setValue()
方法來為單個控件
設(shè)置新值。 setValue() 方法會嚴(yán)格遵循表單組的結(jié)構(gòu)
,并整體性替換控件的值
。
使用 patchValue()
方法可以用對象中所定義的任何屬性
為表單模型進行替換。
setValue() 方法的嚴(yán)格檢查可以幫助你捕獲復(fù)雜表單嵌套中的錯誤,而 patchValue() 在遇到那些錯誤時可能會默默的失敗。
public updateProfile() { // profileForm 模型中只有 firstName 和 street 被修改了。注意,street 是在 address 屬性的對象中被修改的。這種結(jié)構(gòu)是必須的,因為 patchValue() 方法要針對模型的結(jié)構(gòu)進行更新。patchValue() 只會更新表單模型中所定義的那些屬性。 this.profileForm.patchValue({ firstName: 'Nancy' + new Date().getTime(), address: { street: '123 Drew Street' + new Date().getTime() } }); // ERROR Error: Must supply a value for form control with name: 'lastName'. // setValue() 方法會嚴(yán)格遵循表單組的結(jié)構(gòu) this.profileForm.setValue({ firstName: 'Nancy' + new Date().getTime(), address: { street: '123 Drew Street' + new Date().getTime() } }); }
FormArray 是 FormGroup 之外的另一個選擇,用于管理任意數(shù)量的匿名控件。像 FormGroup 實例一樣,你也可以往 FormArray 中動態(tài)插入和移除控件,并且 FormArray 實例的值和驗證狀態(tài)也是根據(jù)它的子控件計算得來的。 不過,你不需要為每個控件定義一個名字作為 key,因此,如果你事先不知道子控件的數(shù)量,這就是一個很好的選擇。
要定義一個動態(tài)表單,請執(zhí)行以下步驟。
導(dǎo)入 FormArray 類。
定義一個 FormArray 控件。
使用 getter 方法訪問 FormArray 控件。
在模板中顯示這個表單數(shù)組
通過把一組(從零項到多項)控件定義在一個數(shù)組中來初始化一個 FormArray。為 profileForm 添加一個 aliases 屬性,把它定義為 FormArray 類型。
import { FormControl, FormGroup, FormArray } from '@angular/forms'; public profileForm = new FormGroup({ firstName: new FormControl(''), lastName: new FormControl(''), address: new FormGroup({ street: new FormControl(''), city: new FormControl(''), state: new FormControl(''), zip: new FormControl('') }), aliases: new FormArray([ new FormControl('1') ]) }); public aliases = (this.profileForm.get('aliases')); public addAlias() { ( this.profileForm.get('aliases')).push(new FormControl('1')); } // 獲取整個 formArray 的數(shù)據(jù) this.profileForm.get('aliases').valueChanges.subscribe({ next: value => { console.log('aliases values is: ' + JSON.stringify(value)); // aliases values is: ["1","3"] } }); // 獲取 formArray 中單個 formControl 的數(shù)據(jù) ( this.profileForm.get('aliases')).controls[0].valueChanges.subscribe({ next: value => { console.log('aliases[0] values is: ' + value); // aliases[0] values is: 0 } })
要想為表單模型添加 aliases,你必須把它加入到模板中供用戶輸入。和 FormGroupNameDirective 提供的 formGroupName 一樣,F(xiàn)ormArrayNameDirective 也使用 formArrayName 在這個 FormArray 實例和模板之間建立綁定
類 | 說明 |
---|---|
AbstractControl | 所有三種表單控件類(FormControl、FormGroup 和 FormArray)的抽象基類。它提供了一些公共的行為和屬性。 |
FormControl | 管理單體表單控件的值和有效性狀態(tài)。它對應(yīng)于 HTML 的表單控件,比如 或 。 |
FormGroup | 管理一組 AbstractControl 實例的值和有效性狀態(tài)。該組的屬性中包括了它的子控件。組件中的頂層表單就是 FormGroup。 |
FormArray | 管理一些 AbstractControl 實例數(shù)組的值和有效性狀態(tài)。 |
FormBuilder | 一個可注入的服務(wù),提供一些用于提供創(chuàng)建控件實例的工廠方法。 |
在模板驅(qū)動表單中,表單模型是隱式的,而不是顯式的。指令 NgModel 為指定的表單元素創(chuàng)建并管理一個 FormControl 實例。
下面的組件使用模板驅(qū)動表單為單個控件實現(xiàn)了同樣的輸入字段。
import { Component } from '@angular/core'; @Component({ selector: 'app-template-favorite-color', template: ` Favorite Color: ` }) export class FavoriteColorComponent { favoriteColor = ''; }
在組件類中直接
把驗證器函數(shù)添加到表單控件模型
上(FormControl)。然后,一旦控件發(fā)生了變化,Angular 就會調(diào)用這些函數(shù)。
驗證器函數(shù)可以是同步函數(shù),也可以是異步函數(shù)。
同步驗證器:這些同步函數(shù)接受一個控件實例,然后返回一組驗證錯誤或 null
。你可以在實例化一個 FormControl 時把它作為構(gòu)造函數(shù)的第二個參數(shù)
傳進去。
異步驗證器 :這些異步函數(shù)接受一個控件實例并返回一個 Promise 或 Observable
,它稍后
會發(fā)出一組驗證錯誤或 null
。在實例化 FormControl 時,可以把它們作為第三個參數(shù)
傳入。
出于性能方面的考慮,只有在所有同步驗證器都通過之后,Angular 才會運行異步驗證器。當(dāng)每一個異步驗證器都執(zhí)行完之后,才會設(shè)置這些驗證錯誤。
在模板驅(qū)動表單中用作屬性的那些內(nèi)置驗證器,比如 required 和 minlength,也都可以作為 Validators 類中的函數(shù)使用
public profileForm = new FormGroup({ firstName: new FormControl('', [ Validators.required ]), }); this.profileForm.get('firstName').valueChanges.subscribe({ next: value => { console.log("First Name is: " + value); console.log(this.profileForm.get('firstName').errors);// { required: true } | null } });
內(nèi)置的驗證器并不是總能精確匹配應(yīng)用中的用例,因此有時你需要創(chuàng)建一個自定義驗證器。
public profileForm = new FormGroup({ firstName: new FormControl('', [ Validators.required, this.forbiddenNameValidator(/bob/i) ]) }); public forbiddenNameValidator(nameRe: RegExp): ValidatorFn { return (control: AbstractControl): {[key: string]: any} | null => { const forbidden = nameRe.test(control.value); return forbidden ? {forbiddenName: {value: control.value}} : null; }; } get firstName() { return this.profileForm.get('firstName'); } this.profileForm.get('firstName').valueChanges.subscribe({ next: value => { console.log("First Name is: " + value); // First Name is: bob console.log(JSON.stringify(this.profileForm.get('firstName').errors));// {"forbiddenName":{"value":"bob"}} | null } });
跨字段交叉驗證器是一種自定義驗證器
,可以對表單中不同字段的值進行比較,并針對它們的組合進行接受或拒絕。
下列交叉驗證的例子說明了如何進行如下操作:
根據(jù)兩個兄弟控件的值驗證響應(yīng)式表單或模板驅(qū)動表單的輸入,
當(dāng)用戶與表單交互過,且驗證失敗后,就會顯示描述性的錯誤信息
要想在單個自定義驗證器中計算這兩個控件,你就必須在它們共同的祖先控件中執(zhí)行驗證: FormGroup。你可以在 FormGroup 中查詢它的子控件,從而讓你能比較它們的值。要想給 FormGroup 添加驗證器,就要在創(chuàng)建時把一個新的驗證器傳給它的第二個參數(shù)。
this.profileForm.valueChanges.subscribe( { next: value => { console.log(JSON.stringify(this.profileForm.errors));// {"identityRevealed":true} | null } }); public profileForm = new FormGroup({ firstName: new FormControl('', [ Validators.required, ]), lastName: new FormControl(''), }, { validators: this.identityRevealedValidator}); public identityRevealedValidator(control: FormGroup): ValidationErrors | null{ const firstName = control.get('firstName'); const lastName = control.get('lastName'); return firstName && lastName && firstName.value === lastName.value ? { identityRevealed: true } : null; };
異步驗證器實現(xiàn)了 AsyncValidatorFn
和 AsyncValidator
接口。它們與其同步版本非常相似,但有以下不同之處。
validate() 函數(shù)必須返回一個 Promise 或可觀察對象
,
返回的可觀察對象必須是有盡
的,這意味著它必須在某個時刻完成(complete)
。要把無盡的可觀察對象轉(zhuǎn)換成有盡的,可以在管道中加入過濾操作符,比如 first、last、take 或 takeUntil。
異步驗證在同步驗證完成后才會發(fā)生
,并且只有在同步驗證成功時才會執(zhí)行。如果更基本的驗證方法已經(jīng)發(fā)現(xiàn)了無效輸入,那么這種檢查順序就可以讓表單避免使用昂貴的異步驗證流程(例如 HTTP 請求)。
let formControl = this.profileForm.get('firstName'); formControl.updateValueAndValidity();
到此,相信大家對“angular中表單的響應(yīng)式和模板驅(qū)動怎么實現(xiàn)”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!