Angular中響應(yīng)式表單的三種更新值方法詳析
前言
眾所周知Angular響應(yīng)式表單相比較模板驅(qū)動(dòng)表單更大操作性、更易測試性。因此,我更推薦這類表單創(chuàng)造方式。
當(dāng)一個(gè)用于修改用戶信息的表單,數(shù)據(jù)的來源總是來自遠(yuǎn)程;而對于一個(gè) FormGroup 的創(chuàng)建總在 ngOnInit 中完成。因此,這里會有一個(gè)表單更新值的問題。
而通常我們會透過 FormGroup 下的三種方式 setValue、patchValue、reset 將值寫入表單當(dāng)中。
當(dāng)然,或許我說的這三種方式時(shí)你壓根就沒有做過,那說明在表單上你依賴的是雙向綁定 [(ngModel)],這本身就不是符合 Angular 響應(yīng)式表單的牛B之處了。因此,在此我們不討論這種這種方式。下面來一起看看詳細(xì)的介紹:
一、創(chuàng)建響應(yīng)式表單
我們模擬一個(gè)用戶信息修改的表單所需要的字段,可能包括:email、nickname 等。
如果以API的方式與現(xiàn)實(shí)字段之間產(chǎn)生一個(gè)關(guān)聯(lián),那么 FormGroup 表示一個(gè)表單,F(xiàn)ormControl 表示表單中的字段。因此,F(xiàn)ormControl 必須包裹在 FromGroup 下面。
下面,我們先簡單的構(gòu)建一個(gè)響應(yīng)式表單。
別忘記導(dǎo)入 ReactiveFormsModule 模塊。
@Component({ selector: 'app-validation', template: ` <form [formGroup]="form" (ngSubmit)="_submitForm(form)"> <input type="email" formControlName="email"> <input type="text" formControlName="nickname"> <button type="submit" [disabled]="form.invalid">Submit</button> </form> ` }) export class UserEditComponent { constructor(private fb: FormBuilder, private route: ActivatedRoute) {} ngOnInit() { this.form = this.fb.group({ email: ['', Validators.compose([Validators.required, Validators.email])], nickname: ['', [Validators.required]] }); this.route.params .switchMap((params: Params) => loadUser(+params['id'])) .subscribe(data => { // Updating value }); } loadUser() { return Observable.of({ email: 'xx@xx.com', nickname: 'cipchk' }).delay(1000); } _submitForm({ value }) { // Save value } }
以上的這些代碼再熟悉不過了。假設(shè) UserEditComponent 是由路由 /user/edit/1 觸發(fā),那么會發(fā)生幾個(gè)幾件事情。
首先,創(chuàng)建一個(gè)空的響應(yīng)式表單 form。
this.form = this.fb.group({ email: ['', Validators.compose([Validators.required, Validators.email])], nickname: ['', [Validators.required]] });
表單的內(nèi)容有 email、nickname 兩個(gè)字段。
- email 必填項(xiàng)且必須是標(biāo)準(zhǔn) Email 格式。
- nickname 必填項(xiàng)。
然而,HTML中,除了 formGroup、formControlName 的配置以外,也看不到任何有關(guān)對表單的校驗(yàn)代碼。但,當(dāng)我們輸入一個(gè)無效 Email 時(shí) input 會自動(dòng)加上 ng-invalid 類。
這便是響應(yīng)式表單的魅力。
現(xiàn)在我們回到正題,將分別針對 setValue、patchValue、reset 三種不同更新表單值實(shí)際上會發(fā)生什么。
二、patchValue
正如名稱那般,打補(bǔ)丁。假如我們在 email 文本框里輸入:xx@xx.com,接著調(diào)用:
this.form.patchValue({ nickname: 'cipchk' });
最終的結(jié)果是兩個(gè)字段同時(shí)擁有值,因?yàn)檫@里我們只對 nickname 設(shè)置了值,而 email 并沒有,那只是先前人為錄入的數(shù)據(jù)。
那么 patchValue 實(shí)際上做了什么呢?
patchValue(value: {[key: string]: any}, options: {onlySelf?: boolean, emitEvent?: boolean} = {}): void { Object.keys(value).forEach(name => { if (this.controls[name]) { this.controls[name].patchValue(value[name], {onlySelf: true, emitEvent: options.emitEvent}); } }); this.updateValueAndValidity(options); }
首先,利用 Object.keys 查找主鍵,并以主鍵名查找相應(yīng)的 FromControl 實(shí)例對象:
Object.keys({ nickname: 'cipchk' }).forEach(name => { console.log(name); }); // [ 'nickname' ]
然后,更新值:
this.controls[name].patchValue(value[name], {onlySelf: true, emitEvent: options.emitEvent});
而 FromControl 實(shí)例的 patchValue 和 FromGroup 不同,他只是單純的更新 FromControle 實(shí)例對象中的 value 值。
value 相當(dāng)于表單實(shí)際值,還記得先前HTML中的 formControlName 就是將實(shí)例與DOM產(chǎn)生聯(lián)系,這也就是為什么不需要在DOM中使用雙向綁定的原因。
三、setValue
跟 patchValue 有一點(diǎn)不一樣,當(dāng)我們提供一個(gè) FromGroup 中并不存在的字段時(shí),會拋出一個(gè)錯(cuò)誤。除此之外,與 patchValue 并無不同。
setValue(value: {[key: string]: any}, options: {onlySelf?: boolean, emitEvent?: boolean} = {}): void { this._checkAllValuesPresent(value); Object.keys(value).forEach(name => { this._throwIfControlMissing(name); this.controls[name].setValue(value[name], {onlySelf: true, emitEvent: options.emitEvent}); }); this.updateValueAndValidity(options); }
主要是 this._throwIfControlMissing(name); 當(dāng)傳遞的對象有一個(gè)不是 FromControl 時(shí)直接拋棄一個(gè) Error。
_throwIfControlMissing(name: string): void { if (!Object.keys(this.controls).length) { throw new Error(` There are no form controls registered with this group yet. If you're using ngModel, you may want to check next tick (e.g. use setTimeout). `); } if (!this.controls[name]) { throw new Error(`Cannot find form control with name: ${name}.`); } }
四、reset
正常情況下,表單需要提供一個(gè)重置按鈕時(shí)調(diào)用此方法。
reset(formState: any = null, options: {onlySelf?: boolean, emitEvent?: boolean} = {}): void { this._applyFormState(formState); this.markAsPristine(options); this.markAsUntouched(options); this.setValue(this._value, options); }
除了恢復(fù)校驗(yàn)狀態(tài)以外。最后一句代碼是調(diào)用 setValue,這等同上一節(jié)說的。因此,當(dāng)我們調(diào)用此方法時(shí),允許我們直接傳遞一個(gè)數(shù)據(jù)對象做為重置后的默認(rèn)值,比如:
<button (click)="form.reset({ nickname: 'xx' })">Reset</button>
重置表單后并設(shè)置 nickname 默認(rèn)值為:xx。
結(jié)論
每一種不同更新值方式都會有不一樣的結(jié)果,當(dāng)我們回頭過看開頭中留下來的:
// Updating value
如果是你,你會怎么寫呢?
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
AngularJS基于MVC的復(fù)雜操作實(shí)例講解
下面小編就為大家分享一篇AngularJS基于MVC的復(fù)雜操作實(shí)例講解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12AngularJS實(shí)現(xiàn)表單驗(yàn)證功能
這篇文章主要為大家詳細(xì)介紹了AngularJS實(shí)現(xiàn)表單驗(yàn)證功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01使用Angular 6創(chuàng)建各種動(dòng)畫效果的方法
Angular能夠讓我們創(chuàng)建出具有原生表現(xiàn)效果的動(dòng)畫。我們將通過本文學(xué)習(xí)到如何使用Angular 6來創(chuàng)建各種動(dòng)畫效果。在此,我們將使用Visual Studio Code來進(jìn)行示例演示。感興趣的朋友跟隨小編一起看看吧2018-10-10AngularJS基礎(chǔ) ng-init 指令簡單示例
本文主要介紹AngularJS ng-init 指令,這里幫大家整理了關(guān)于ng-init 指令的基本知識資料,并附有簡單的代碼示例,有需要學(xué)習(xí)的小伙伴可以參考下2016-08-08Angular依賴注入系統(tǒng)里Injection token PLATFORM_ID使用場景詳解
這篇文章主要為大家介紹了Angular依賴注入系統(tǒng)里Injection token PLATFORM_ID使用場景詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11ionic4+angular7+cordova上傳圖片功能的實(shí)例代碼
ionic是一個(gè)垮平臺開發(fā)框架,可通過web技術(shù)開發(fā)出多平臺的應(yīng)用。這篇文章主要介紹了ionic4+angular7+cordova上傳圖片功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下2019-06-06AngularJS實(shí)現(xiàn)動(dòng)態(tài)添加Option的方法
這篇文章主要介紹了AngularJS實(shí)現(xiàn)動(dòng)態(tài)添加Option的方法,涉及AngularJS事件響應(yīng)及頁面元素動(dòng)態(tài)操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-05-05