這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)?lái)有關(guān)Angular19 中如何自定義表單控件,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)!專注于網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開(kāi)發(fā)、重慶小程序開(kāi)發(fā)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了阜南免費(fèi)建站歡迎大家使用!
1 需求
當(dāng)開(kāi)發(fā)者需要一個(gè)特定的表單控件時(shí)就需要自己開(kāi)發(fā)一個(gè)和默認(rèn)提供的表單控件用法相似的控件來(lái)作為表單控件;自定義的表單控件必須考慮模型和視圖之間的數(shù)據(jù)怎么進(jìn)行交互
2 官方文檔 ->點(diǎn)擊前往
Angular為開(kāi)發(fā)者提供了ControlValueAccessor接口來(lái)輔助開(kāi)發(fā)者構(gòu)建自定義的表單控件,開(kāi)發(fā)者只需要在自定義表單控件類中實(shí)現(xiàn)ControlValueAccessor接口中的方法就可以實(shí)現(xiàn)模型和視圖之間的數(shù)據(jù)交互
interface ControlValueAccessor { writeValue(obj: any): void registerOnChange(fn: any): void registerOnTouched(fn: any): void setDisabledState(isDisabled: boolean)?: void }
2.1 writeValue
writeValue(obj: any): void
該方法用于將值寫入到自定義表單控件中的元素;
這個(gè)參數(shù)值(obj)是使用這個(gè)自定義表單控件的組件通過(guò)模板表單或者響應(yīng)式表單的數(shù)據(jù)綁定傳過(guò)來(lái)的;
在自定義表單控件的類中只需要將這個(gè)值(obj)賦值給一個(gè)成員變量即可,自定義表單控件的視圖就會(huì)通過(guò)屬性綁定顯示出來(lái)這個(gè)值
2.2 registerOnChange
registerOnChange(fn: any): void
自定義表單控件的數(shù)據(jù)發(fā)生變化時(shí)會(huì)觸發(fā)registerOnChange方法,該方用于如何處理自定義表單控件數(shù)據(jù)的變化;
registerOnChange方法接收的參數(shù)(fn)其實(shí)是一個(gè)方法,該方法負(fù)責(zé)處理變化的數(shù)據(jù)
當(dāng)自定義控件數(shù)據(jù)變化時(shí)就會(huì)自動(dòng)調(diào)用fn執(zhí)行的方法,但是通常的做法是自定義一個(gè)方法 propagateChange 讓自定義的方法指向fn,這樣當(dāng)數(shù)據(jù)變化時(shí)只需要調(diào)用 propagateChange 就可以對(duì)變化的數(shù)據(jù)進(jìn)行處理
2.3 registerOnTouched
registerOnTouched(fn: any): void
表單控件被觸摸時(shí)會(huì)觸發(fā)registerOnTouched方法,具體細(xì)節(jié)待更新......2018-1-31 11:18:33
2.4 setDisabledState
setDisabledState(isDisabled: boolean)?: void
待更新......2018-1-31 11:19:30
3 編程步驟
3.1 創(chuàng)建自定義表單控件組件
當(dāng)前計(jì)數(shù)為:{{countNumber}}
HTML
import { Component, OnInit } from '@angular/core'; import { ControlValueAccessor } from '@angular/forms'; @Component({ selector: 'app-counter', templateUrl: './counter.component.html', styleUrls: ['./counter.component.scss'] }) export class CounterComponent implements OnInit { countNumber: number = 0; constructor() { } ngOnInit() { } onIncrease() { this.countNumber++; } onDecrease() { this.countNumber--; } }
3.1.1 功能描述
點(diǎn)擊增加按鈕時(shí)當(dāng)前計(jì)數(shù)會(huì)增加1,點(diǎn)擊減少按鈕時(shí)當(dāng)前計(jì)數(shù)會(huì)剪1
3.1.2 直接在其他組件中使用時(shí)會(huì)報(bào)錯(cuò)
報(bào)錯(cuò)信息如下:
錯(cuò)誤信息是說(shuō)我們我們使用的組件
3.2 如何讓
3.2.1 實(shí)現(xiàn) ControlValueAccessor 接口
export class CounterComponent implements OnInit, ControlValueAccessor { countNumber: number = 0; constructor() { } ngOnInit() { } onIncrease() { this.countNumber++; } onDecrease() { this.countNumber--; } /**將數(shù)據(jù)從模型傳輸?shù)揭晥D */ writeValue(obj: any): void { } /**將數(shù)據(jù)從視圖傳播到模型 */ registerOnChange(fn: any): void { } registerOnTouched(fn: any): void { } setDisabledState?(isDisabled: boolean): void { } }
3.2.2 指定依賴信息providers
import { Component, OnInit, forwardRef } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; @Component({ selector: 'app-counter', templateUrl: './counter.component.html', styleUrls: ['./counter.component.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => CounterComponent), multi: true } ] }) export class CounterComponent implements OnInit, ControlValueAccessor { countNumber: number = 0; constructor() { } ngOnInit() { } onIncrease() { this.countNumber++; } onDecrease() { this.countNumber--; } /**將數(shù)據(jù)從模型傳輸?shù)揭晥D */ writeValue(obj: any): void { } /**將數(shù)據(jù)從視圖傳播到模型 */ registerOnChange(fn: any): void { } registerOnTouched(fn: any): void { } setDisabledState?(isDisabled: boolean): void { } }
3.2.3 待修復(fù)bug
雖然可以正常運(yùn)行,但是表單控件中的元素接受不到使用表單控件那個(gè)組件中表單模型傳過(guò)來(lái)的數(shù)據(jù),表單控件變化的數(shù)據(jù)也無(wú)法回傳到使用表單控件那個(gè)組件中的表單模型中去;簡(jiǎn)而言之,就是模型和視圖之間無(wú)法進(jìn)行數(shù)據(jù)交互
3.3 實(shí)習(xí)那模型和試圖的數(shù)據(jù)交互
3.3.1 模型到視圖
重構(gòu)自定義表單控件類中的 writeValue 方法
技巧01:writeValue 方法中的參數(shù)是使用自定義表單控件的那個(gè)組件通過(guò)表單的數(shù)據(jù)綁定傳進(jìn)來(lái)的
3.3.2 視圖到模型
》自定義一個(gè)方法來(lái)處理自定義表單控件中的變化數(shù)據(jù)
propagateChange = (_: any) => {};
》重構(gòu)自定義表單控件類中的 registerOnChange 方法
/**將數(shù)據(jù)從視圖傳播到模型 */ registerOnChange(fn: any): void { this.propagateChange = fn; }
》在數(shù)據(jù)變化的地方調(diào)用那個(gè)自定義的方法
3.4 自定義表單控件組件代碼匯總
當(dāng)前計(jì)數(shù)為:{{countNumber}}
HTML
import { Component, OnInit, forwardRef } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; @Component({ selector: 'app-counter', templateUrl: './counter.component.html', styleUrls: ['./counter.component.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => CounterComponent), multi: true } ] }) export class CounterComponent implements OnInit, ControlValueAccessor { countNumber: number = 0; propagateChange = (_: any) => {}; constructor() { } ngOnInit() { } onIncrease() { this.countNumber++; this.propagateChange(this.countNumber); } onDecrease() { this.countNumber--; this.propagateChange(this.countNumber); } /**將數(shù)據(jù)從模型傳輸?shù)揭晥D */ writeValue(obj: any): void { this.countNumber = obj; } /**將數(shù)據(jù)從視圖傳播到模型 */ registerOnChange(fn: any): void { /**fn其實(shí)是一個(gè)函數(shù),當(dāng)視圖中的數(shù)據(jù)改變時(shí)就會(huì)調(diào)用fn指向的這個(gè)函數(shù),從而達(dá)到將數(shù)據(jù)傳播到模型的目的 */ this.propagateChange = fn; // 將fn的指向賦值給this.propagateChange,在需要將改變的數(shù)據(jù)傳到模型時(shí)只需要調(diào)用this.propagateChange方法即可 } registerOnTouched(fn: any): void { } setDisabledState?(isDisabled: boolean): void { } }
3.5 使用自定義表單控件的那個(gè)組件的代碼匯總
技巧01:如果自定義表單控件和使用自定義表單控件的組件都在不在同一個(gè)模塊時(shí)需要對(duì)自定義表單控件對(duì)應(yīng)組件進(jìn)行導(dǎo)出和導(dǎo)入操作
面板模板面板測(cè)試內(nèi)容
2018-1-22 10:22:20自定義提取表單控件綠線上是自定義提取的表單控件顯示的內(nèi)容
綠線下是使用自定義表單控件時(shí)表單的實(shí)時(shí)數(shù)據(jù) 表單控件的值為:{{myForm.value | json}}
2018-1-31 10:09:17提取表單控件2018-1-27 21:51:45ngIf指令測(cè)試
ngif變量的值為true
ngif變量的值為false
2018-1-27 16:58:17RXJS使用測(cè)試內(nèi)容
2018-1-23 21:14:49自定義驗(yàn)證器2018-1-23 11:06:01響應(yīng)式表單
表單整體信息如下:
表單數(shù)據(jù)有效性:{{testForm.valid}}
表單數(shù)據(jù)為:{{testForm.value | json}}
獲取單個(gè)或多個(gè)FormControl:{{testForm.controls['email'] }}
email輸入框的信息如下:
有效性:{{testForm.get('email').valid}}
email輸入框的錯(cuò)誤信息為:{{testForm.get('email').errors | json}}
required驗(yàn)證結(jié)果:{{testForm.hasError('required', 'email') | json}}
minLength驗(yàn)證結(jié)果:{{ testForm.hasError('minLength', 'email') | json }}
hello:{{ testForm.controls['email'].errors | json }}
password輸入框啊的信息如下:
有效性:{{testForm.get('password').valid}}
password輸入框的錯(cuò)誤信息為:{{testForm.get('password').errors | json }}
required驗(yàn)證結(jié)果:{{testForm.hasError('required', 'password') | json}}
data變量:{{data}}
2018-1-22 15:58:43-->利用響應(yīng)式編程實(shí)現(xiàn)表單元素雙向綁定 姓名為:{{name.value}}2018-1-22 11:12:35模板表單名為desc的表單控件的值為:{{ a.value }}
2018-1-22 10:19:31md-chekbox的使用測(cè)試 測(cè)試checkbox被選中啦
2018-1-18 14:02:20md-tooltip的使用鼠標(biāo)放上去2018-1-18 14:26:58md-select的使用{{taskList.name}} 2018-1-18 14:26:58ngNonBindable指令的使用描述
使用了ngNonBindable的標(biāo)簽,會(huì)將該標(biāo)簽里面的元素內(nèi)容全部都看做時(shí)純文本
例子
{{taskLists | json }} ← 這是{{taskLists | json }}渲染的內(nèi)容
2018-1-19 09:34:26
HTML
import { Component, OnInit, HostListener, Inject} from '@angular/core'; import { FormControl, FormGroup, FormBuilder, Validators } from '@angular/forms'; import { Http } from '@angular/http'; import { QuoteService } from '../../service/quote.service'; @Component({ selector: 'app-test01', templateUrl: './test01.component.html', styleUrls: ['./test01.component.scss'] }) export class Test01Component implements OnInit { countNumber: number = 9; outerCounterValue: number = 5; ngif = true; loginForm: FormGroup; testForm: FormGroup; data: any; name: FormControl = new FormControl(); desc: string = 'hello boy'; taskLists = [ {label: 1, name: '進(jìn)行中'}, {label: 2, name: '已完成'} ]; constructor( private formBuilder: FormBuilder, private http: Http, @Inject('BASE_CONFIG') private baseConfig, private quoteService: QuoteService ) {} ngOnInit() { this.testForm = new FormGroup({ email: new FormControl('', [Validators.required, Validators.minLength(4)], []), password: new FormControl('', [Validators.required], []) }); this.name.valueChanges .debounceTime(500) .subscribe(value => alert(value)); this.loginForm = this.formBuilder.group({ username: ['', [Validators.required, Validators.minLength(4), this.myValidator], []], userpwd: ['', [Validators.required, Validators.minLength(6)], []] }); this.quoteService.test() .subscribe(resp => console.log(resp)); } onChangeNgifValue() { if (this.ngif == false) { this.ngif = true; } else { this.ngif = false; } } @HostListener('keyup.enter') onTestNgModelClick() { alert('提交'); } onTestClick() { // this.data = this.testForm.get('email').value; // console.log(this.testForm.getError); console.log(this.testForm.controls['email']); } onTestLogin() { console.log(this.loginForm.value); if (this.loginForm.valid) { console.log('登陸數(shù)據(jù)合法'); } else { console.log('登陸數(shù)據(jù)不合法'); console.log(this.loginForm.controls['username'].errors); console.log(this.loginForm.get('userpwd').errors); } } myValidator(fc: FormControl): {[key: string]: any} { const valid = fc.value === 'admin'; return valid ? null : {myValidator: {requiredUsername: 'admin', actualUsername: fc.value}}; } }
3.6 初始化效果展示
上述就是小編為大家分享的Angular19 中如何自定義表單控件了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。