angular4自定義組件非input元素實(shí)現(xiàn)ngModel雙向數(shù)據(jù)綁定的方法
在angular里我們一般都是給input元素添加[(ngModel)]="value"實(shí)現(xiàn)數(shù)據(jù)雙向綁定,如果想實(shí)現(xiàn)自定義的組件上實(shí)現(xiàn)ngModel雙向數(shù)據(jù)綁定應(yīng)該怎么辦吶。。。
網(wǎng)上找了一下,沒(méi)看懂記錄一下。
場(chǎng)景:組件能獲取父組件通過(guò)ngModel綁定的值,能通過(guò)ngModel改變父組件對(duì)應(yīng)的數(shù)據(jù)。如下代碼:
<app-child [(ngModel])="appData"></app-child>
1、先貼出效果圖:

2、下面是app-child組件的代碼:
import { Component, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css'],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => ChildComponent),
multi: true
}]
})
export class ChildComponent implements ControlValueAccessor {
constructor() { }
_data: any;
add () {
this.childData ++;
}
change = (value: any) => {}; // 先定義一個(gè)方法,很重要,用于接收registerOnChange()方法里傳遞回來(lái)的方法,然后通過(guò)這個(gè)方法就能通知到外部組件數(shù)據(jù)更新。
set childData(value: number) { // childData被更改走該方法
this._data = value;
this.change(this._data); // 將更新后的數(shù)據(jù)通知到外部組件
}
get childData() { // 頁(yè)面或者方法里面有調(diào)用childData就會(huì)走該方法
return this._data;
}
writeValue(val): void { // 初始化時(shí),獲取并監(jiān)聽(tīng)父組件通過(guò)ngModel傳遞進(jìn)來(lái)的數(shù)據(jù)
if (val) {
this._data = val;
}
}
registerOnChange(fn: any): void { // 初始化后,執(zhí)行該方法,并保存控件接收到 change 事件后,調(diào)用的函數(shù)
this.change = fn;
}
registerOnTouched(fn: any): void {
}
}
3、下面開(kāi)始說(shuō)下實(shí)現(xiàn)的過(guò)程吧:
如果添加ngModel后報(bào)如下錯(cuò)誤,檢查組件對(duì)應(yīng)的Module文件有沒(méi)有導(dǎo)入FormsModule

import { FormsModule } from '@angular/forms';
@NgModule({
...
imports: [
...,
FormsModule
],
...
})
import FormsModule后,控制臺(tái)任然會(huì)報(bào)錯(cuò):

這是因?yàn)槲覀冃枰谑褂胣gModel的組件里實(shí)現(xiàn)ControlValueAccessor的接口方法。
先引入和使用我們必須使用的配置:
import { Component, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css'],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => ChildComponent), // 這里的組件名為當(dāng)前組件的名字
multi: true
}]
})
export class ChildComponent implements ControlValueAccessor {
constructor() { }
childData = 2;
}
處理完成后控制臺(tái)的報(bào)錯(cuò)信息已經(jīng)改變:

這是因?yàn)镃ontrolValueAccessor的接口有幾個(gè)必須存在的方法,會(huì)自動(dòng)去調(diào)用:
writeValue(val): void {
}
registerOnChange(fn: any): void {
}
registerOnTouched(fn: any): void {
}
- 初始化的時(shí)候調(diào)用
writeValue()方法,將會(huì)使用表單模型中對(duì)應(yīng)的初始值作為參數(shù)(也就是ngModel里的值)。 - registerOnChange() 可以用來(lái)通知外部,組件已經(jīng)發(fā)生變化。
- registerOnTouched() 方法用于設(shè)置當(dāng)控件接收到 touched 事件后,調(diào)用的函數(shù)。
知道了這三個(gè)方法后,我們就可以在writeValue方法里給組件設(shè)置父組件通過(guò)ngModel傳遞過(guò)來(lái)的值了。如:
writeValue(val): void {
if (val) {
this.childData = val;
}
}
那么怎么將組件里更新的數(shù)據(jù)傳遞給父組件吶。
registerOnChange(fn: any): void { // 初始化后,執(zhí)行該方法,并保存控件接收到 change 事件后,調(diào)用的函數(shù)
this.change = fn;
}
writeValue()方法后就會(huì)執(zhí)行registerOnChange()方法,我們就是通過(guò)該方法傳遞回來(lái)的方法參數(shù)來(lái)通知到外部組件數(shù)據(jù)更新的,所以我們要在最開(kāi)始就定義一個(gè)方法來(lái)接收。
change = (value: any) => {};
// 先定義一個(gè)方法,很重要,用于接收registerOnChange()方法里傳遞回來(lái)的方法,然后通過(guò)這個(gè)方法就能通知到外部組件數(shù)據(jù)更新。
然后就可以通過(guò)change方法通知外部組件了
set childData(value: number) { // childData被更改走該方法
this._data = value;
this.change(this._data); // 將更新后的數(shù)據(jù)通知到外部組件
}
最開(kāi)始貼出來(lái)的代碼,中間使用了set 和get去處理了數(shù)據(jù),在get childData()方法里打斷點(diǎn)發(fā)現(xiàn)會(huì)執(zhí)行很多次該方法,其實(shí)也可以修改成通過(guò)更新數(shù)據(jù)的時(shí)候就直接調(diào)用change()方法來(lái)通知外部組件數(shù)據(jù)更新,如下:
import { Component, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css'],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => ChildComponent),
multi: true
}]
})
export class ChildComponent implements ControlValueAccessor {
constructor() { }
_data: any;
childData = 1;
add () {
this.childData ++;
this.change(this.childData);
}
change = (value: any) => {}; // 先定義一個(gè)方法,很重要,用于接收registerOnChange()方法里傳遞回來(lái)的方法,然后通過(guò)這個(gè)方法就能通知到外部組件數(shù)據(jù)更新。
writeValue(val): void { // 初始化時(shí),獲取并監(jiān)聽(tīng)父組件通過(guò)ngModel傳遞進(jìn)來(lái)的數(shù)據(jù)
if (val) {
this.childData = val;
}
}
registerOnChange(fn: any): void { // 初始化后,執(zhí)行該方法,并保存控件接收到 change 事件后,調(diào)用的函數(shù)
this.change = fn;
}
registerOnTouched(fn: any): void {
}
}
中間不用使用get和set,不知道兩種方法哪種更好。
其實(shí)通過(guò)子組件通知父級(jí)組件數(shù)據(jù)更新,可以使用@Input和@Output來(lái)實(shí)現(xiàn)的,如果是@Input獲取的父級(jí)組件的數(shù)據(jù),父級(jí)組件數(shù)據(jù)更新,子組件需要在ngOnChanges生命周期里去監(jiān)聽(tīng)對(duì)應(yīng)的數(shù)據(jù)變更并處理相應(yīng)的邏輯。
不過(guò)在自定義組件上使用ngModel實(shí)現(xiàn)數(shù)據(jù)的雙向綁定還可以用作表單處理上,比如表單模板和表單驗(yàn)證。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
AngularJS 中使用Swiper制作滾動(dòng)圖不能滑動(dòng)的解決方法
Swiper是目前較為流行的移動(dòng)端觸摸滑動(dòng)插件,因?yàn)槠浜?jiǎn)單好用易上手,受到很多前端開(kāi)發(fā)者的歡迎。這篇文章主要介紹了AngularJS 中使用Swiper制作滾動(dòng)圖不能滑動(dòng)的解決方法,需要的朋友可以參考下2016-11-11
AngularJS 使用ng-repeat報(bào)錯(cuò) [ngRepeat:dupes]
這篇文章主要介紹了AngularJS 使用ng-repeat報(bào)錯(cuò) [ngRepeat:dupes] 的相關(guān)資料,需要的朋友可以參考下2017-01-01
AngularJS路由切換實(shí)現(xiàn)方法分析
這篇文章主要介紹了AngularJS路由切換實(shí)現(xiàn)方法,結(jié)合具體實(shí)例形式分析了AngularJS路由切換的實(shí)現(xiàn)步驟與相關(guān)操作技巧,需要的朋友可以參考下2017-03-03
Webpack 實(shí)現(xiàn) AngularJS 的延遲加載
這篇文章主要介紹了Webpack 實(shí)現(xiàn) AngularJS 的延遲加載的相關(guān)資料,需要的朋友可以參考下2016-03-03
Angular4.x Event (DOM事件和自定義事件詳解)
今天小編就為大家分享一篇Angular4.x Event (DOM事件和自定義事件詳解),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-10-10
簡(jiǎn)單說(shuō)說(shuō)angular.json文件的使用
這篇文章主要介紹了簡(jiǎn)單說(shuō)說(shuō)angular.json文件的使用,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-10-10
angularjs實(shí)現(xiàn)與服務(wù)器交互分享
AngularJS是Google開(kāi)發(fā)的純客戶(hù)端JavaScript技術(shù)的WEB框架,用于擴(kuò)展、增強(qiáng)HTML功能,它專(zhuān)為構(gòu)建強(qiáng)大的WEB應(yīng)用而設(shè)計(jì)。2014-06-06
AngularJS入門(mén)教程之服務(wù)(Service)
本文主要介紹 AngularJS Service,這里整理了AngularJS Servic的詳細(xì)資料,并提供代碼實(shí)例,有需要的小伙伴可以參考下2016-07-07
詳解Angular項(xiàng)目中共享模塊的實(shí)現(xiàn)
本文主要介紹了Angular的共享模塊的實(shí)現(xiàn),對(duì)此感興趣的同學(xué),可以實(shí)驗(yàn)一下2021-05-05
AngularJS實(shí)現(xiàn)表單手動(dòng)驗(yàn)證和表單自動(dòng)驗(yàn)證
本文是對(duì)AngularJS表單驗(yàn)證,手動(dòng)驗(yàn)證或自動(dòng)驗(yàn)證的講解,對(duì)學(xué)習(xí)JavaScript編程技術(shù)有所幫助,感興趣的小伙伴們可以參考一下2015-12-12

