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 ...
随机推荐
- Python学习简单练习-99乘法表
__author__ = 'ZFH'#-*- coding:utf-8 -*-for i in range(10): #外层循环,range(10),1-9 for j in range(1,i+1) ...
- Mybaties下的分页功能的实现
jsp页面 <!-- 页码 --> <div class="ipRListNav2"> <a href="zyxx.do?findZyxx& ...
- Oracle rownum影响运行计划
今天调优一条SQL语句,因为SQL比較复杂,用autotrace非常难一眼看出哪里出了问题,直接上10046. SELECT AB.* FROM (SELECT A.*, rownum RN FROM ...
- android自己定义圆盘时钟
自己定义圆盘时钟的大概流程:由于圆盘时钟的圆盘是不须要动的,所以不必要加在自己定义的view里面,在view里面仅仅须要绘制秒针和分针时针并控其转动就可以. 下面就是自己定义view的主要代码: pa ...
- 如何解读「量子计算应对大数据挑战:中国科大首次实现量子机器学习算法」?——是KNN算法吗?
作者:知乎用户链接:https://www.zhihu.com/question/29187952/answer/48519630 我居然今天才看到这个问题,天……本专业,有幸听过他们这个实验的组会来 ...
- OWIN是Open Web Server Interface for .NET
http://owin.org/ Servers and Hosts Katana Nowin Suave Frameworks Jasper Nancy SignalR WebApi WebShar ...
- OpenGL编程逐步深入(十)索引绘制
准备知识 OpenGl提供了一些绘图函数.到目前为止我们使用的glDrawArrays绘图函数属于"顺序绘制".这意味着顶点缓冲区从指定的偏移量开始被扫描,每X(点为1,直线为2等 ...
- CentOS7.4-btrfs管理及使用
btrfs, B-tree File System, GPL开源文件系统, 支持CoW即读时写入. 核心特性: 多物理卷支持; btrfs可由多个底层磁盘组成 支持RAID mkfs.btrfs 命令 ...
- NodeJS学习笔记 (14)URL查询字符串-querystring(ok)
模块概述 在nodejs中,提供了querystring这个模块,用来做url查询参数的解析,使用非常简单. 模块总共有四个方法,绝大部分时,我们只会用到 .parse(). **.stringify ...
- yii2-Ueditor百度编辑器
今天在网上看了下有关图片上传的教程,历经挫折才调试好,现在把相关代码及其说明贴出来,以供初次使用的朋友们参考. 资源下载 yii2.0-ueditor下载路径: https://link.jiansh ...