angular4自定义组件非input元素实现ngModel双向数据绑定
在angular里我们一般都是给input元素添加[(ngModel)]="value"实现数据双向绑定,如果想实现自定义的组件上实现ngModel双向数据绑定应该怎么办呐。。。
网上找了一下,没看懂记录一下。
场景:组件能获取父组件通过ngModel绑定的值,能通过ngModel改变父组件对应的数据。如下代码:
<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) => {}; // 先定义一个方法,很重要,用于接收registerOnChange()方法里传递回来的方法,然后通过这个方法就能通知到外部组件数据更新。
set childData(value: number) { // childData被更改走该方法
this._data = value;
this.change(this._data); // 将更新后的数据通知到外部组件
}
get childData() { // 页面或者方法里面有调用childData就会走该方法
return this._data;
}
writeValue(val): void { // 初始化时,获取并监听父组件通过ngModel传递进来的数据
if (val) {
this._data = val;
}
}
registerOnChange(fn: any): void { // 初始化后,执行该方法,并保存控件接收到 change 事件后,调用的函数
this.change = fn;
}
registerOnTouched(fn: any): void {
}
}
3、下面开始说下实现的过程吧:
如果添加ngModel后报如下错误,检查组件对应的Module文件有没有导入FormsModule

import { FormsModule } from '@angular/forms';
@NgModule({
...
imports: [
...,
FormsModule
],
...
})
import FormsModule后,控制台任然会报错:

这是因为我们需要在使用ngModel的组件里实现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), // 这里的组件名为当前组件的名字
multi: true
}]
})
export class ChildComponent implements ControlValueAccessor {
constructor() { }
childData = 2;
}
处理完成后控制台的报错信息已经改变:

这是因为ControlValueAccessor的接口有几个必须存在的方法,会自动去调用:
writeValue(val): void {
}
registerOnChange(fn: any): void {
}
registerOnTouched(fn: any): void {
}
- 初始化的时候调用
writeValue()方法,将会使用表单模型中对应的初始值作为参数(也就是ngModel里的值)。 - registerOnChange() 可以用来通知外部,组件已经发生变化。
- registerOnTouched() 方法用于设置当控件接收到 touched 事件后,调用的函数。
知道了这三个方法后,我们就可以在writeValue方法里给组件设置父组件通过ngModel传递过来的值了。如:
writeValue(val): void {
if (val) {
this.childData = val;
}
}
那么怎么将组件里更新的数据传递给父组件呐。
registerOnChange(fn: any): void { // 初始化后,执行该方法,并保存控件接收到 change 事件后,调用的函数
this.change = fn;
}
writeValue()方法后就会执行registerOnChange()方法,我们就是通过该方法传递回来的方法参数来通知到外部组件数据更新的,所以我们要在最开始就定义一个方法来接收。
change = (value: any) => {}; // 先定义一个方法,很重要,用于接收registerOnChange()方法里传递回来的方法,然后通过这个方法就能通知到外部组件数据更新。
然后就可以通过change方法通知外部组件了
set childData(value: number) { // childData被更改走该方法
this._data = value;
this.change(this._data); // 将更新后的数据通知到外部组件
}
最开始贴出来的代码,中间使用了set 和get去处理了数据,在get childData()方法里打断点发现会执行很多次该方法,其实也可以修改成通过更新数据的时候就直接调用change()方法来通知外部组件数据更新,如下:
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) => {}; // 先定义一个方法,很重要,用于接收registerOnChange()方法里传递回来的方法,然后通过这个方法就能通知到外部组件数据更新。
writeValue(val): void { // 初始化时,获取并监听父组件通过ngModel传递进来的数据
if (val) {
this.childData = val;
}
}
registerOnChange(fn: any): void { // 初始化后,执行该方法,并保存控件接收到 change 事件后,调用的函数
this.change = fn;
}
registerOnTouched(fn: any): void {
}
}
中间不用使用get和set,不知道两种方法哪种更好。
其实通过子组件通知父级组件数据更新,可以使用@Input和@Output来实现的,如果是@Input获取的父级组件的数据,父级组件数据更新,子组件需要在ngOnChanges生命周期里去监听对应的数据变更并处理相应的逻辑。
不过在自定义组件上使用ngModel实现数据的双向绑定还可以用作表单处理上,比如表单模板和表单验证。
angular4自定义组件非input元素实现ngModel双向数据绑定的更多相关文章
- angular学习笔记(四)- input元素的ng-model属性
input元素的ng-model属性: 用于将input的值和变量的值进行双向绑定 <!DOCTYPE html> <html ng-app> <head> < ...
- 前端 | 自定义组件 v-model:Vue 如何实现双向绑定
v-model 是 Vue 中一个常用的指令,常用于表单中的数据绑定.如下基本用法想必大家都很熟悉,data 中的 checked 属性的值就会随着多选框的状态实时变化. <el-checkbo ...
- 【vue】---- v-model在自定义组件中的使用
1. v-model简介 可以用 v-model 指令在表单 <input>.<textarea> 及 <select> 元素上创建双向数据绑定,它的本质是一个语法 ...
- 组件使用v-model、$listeners、.sync(区别于v-model的双向数据绑定)
自定义组件 自定义组件的v-model 首先我们先说一下在自定义组件中使用v-model的必要条件 在自定义的组件中要有input(这里我们先不讨论单选复选框) 在自定义组件的模板对象中要有props ...
- ionic3+angular4开发混合app 之自定义组件
这里主要是记录ionic3+angular4开发混合app时自定义组件,我想自定义组件的方法和angular4应该类似,具体在纯angular4中自定义组件,暂时没有实践,个人觉得差别不大,之后实践了 ...
- ionic3.x angular4.x ng4.x 自定义组件component双向绑定之自定义计数器
本文主要示例在ionic3.x环境下实现一个自定义计数器,实现后最终效果如图: 1.使用命令创建一个component ionic g component CounterInput 类似的命令还有: ...
- 玩转angularJs——通过自定义ng-model,不仅仅只是input可以实现双向数据绑定
体验更优排版请移步原文:http://blog.kwin.wang/programming/angularJs-user-defined-ngmodel.html angularJs双向绑定特性在开发 ...
- vue input框type=number 保留两位小数自定义组件
第一步:自定义组件MyNumberInput.vue<template> <input class="numberInput" type="number ...
- angular4 自定义表单组件
自定义表单组件分为单值组件和多值组件. 单值组件:input/select/radio/textarea 多值组件:checkbox/tree组件 条件: 1.必须实现ControlValueAcce ...
随机推荐
- Node.js使用cnpm
npm是Node.js中维护第三方库.模块的工具,可是国外的速度非常悲剧,这里有一个中国的源cnpm. http://cnpmjs.org/ 须要在命令行中执行 npm install -g cnpm ...
- 实现浮点数的四舍五入RoundOff,保留几位小数
直接上代码,非常简短 double myRound(double d,int n) { d = d*pow(10,n); d += 0.5; d = (long)d; d = d/pow(10,n); ...
- Python 入门学习 -----变量及基础类型(元组,列表,字典,集合)
Python的变量和数据类型 1 .python的变量是不须要事先定义数据类型的.能够动态的改变 2. Python其中一切皆对象,变量也是一个对象,有自己的属性和方法 我们能够通过 来查看变量的类型 ...
- 【金阳光測试】基于控件核心技术探讨---Android自己主动化系列(2)---2013年5月
第一讲分享了下安卓自己主动化一些概况和一些自己主动化框架现状和技术可以解决什么样的问题. 这次课就深入到android世界里面.遨游.翱翔.深入了解自己主动化測试核心技术. 搞过编程开发的同学听到in ...
- ubuntu,jdk安装成功后,点击eclipse,提示信息A Java RunTime Environment (JRE) or Java Development Kit (JDK)
A Java RunTime Environment (JRE) or Java Development Kit (JDK) must be available in order to run Ecl ...
- python 字符串匹配问题
想匹配html = <div class="back fl"><a href="javascript:void(0);" onclick=&q ...
- laravel模板机制
@extends('layouts.master') @section('title', 'Page Title') @section('sidebar') @parent <p>This ...
- yii2-Ueditor百度编辑器
今天在网上看了下有关图片上传的教程,历经挫折才调试好,现在把相关代码及其说明贴出来,以供初次使用的朋友们参考. 资源下载 yii2.0-ueditor下载路径: https://link.jiansh ...
- 通过JMeter来测试Quick Easy FTP Server的上传与下载性能
FTP性能测试 1.1背景说明 本测试选用的是一个小型的FTP服务器软件:Quick Easy FTP Server.Quick Easy FTP Server是一个全中文的FTP服务器软件,反应迅速 ...
- 我的投资案例(3)-看好互联网和金融两大朝阳行业,参投入股垂直金融招聘平台"职业梦CareerDream.cn"
作为一名喜欢读书,关注中国和欧美国家发展的知识青年, 同时作为一名程序员和对金融投资感兴趣的业余爱好者,本人一直看好 以IT互联网为代表的科技和以投资VC为代表的金融,这2大朝阳行业的发展. ...