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 ...
随机推荐
- java 项目 导入成功后jsp页面报错处理方法
本人新导入一个maven项目可是jsp页面一直报错,我先按照网上的经验操作如下步骤: 在pom.xml配置文件中添加上javax.servlet的相关依赖: <dependency> & ...
- Leetcode-Best Time to Buy and Sell Stock -java
题目: Say you have an array for which the ith element is the price of a given stock on day i. If you w ...
- Mahout推荐算法API具体解释【一起学Mahout】
阅读导读: 1.mahout单机内存算法实现和分布式算法实现分别存在哪些问题? 2.算法评判标准有哪些? 3.什么会影响算法的评分? 1. Mahout推荐算法介绍 Mahout推荐算法,从数据处理能 ...
- HDOJ 2828 Lamp DLX反复覆盖
DLX反复覆盖模版题: 每一个开关两个状态.但仅仅能选一个,建2m×n的矩阵跑DLX模版.. .. Lamp Time Limit: 2000/1000 MS (Java/Others) Mem ...
- Html学习(三) 分类学习
代码: <h1>这是一级分类吗</h1> <h2>这是二级分类吗</h2> <h3>这是三级分类吗 </h3> 效果: 介绍: ...
- 从Oracle Database 角度来看浪潮天梭K1主机的操作系统选择
背景: 浪潮天梭k1主机.事实上分好几个类别: K1-950 intel 安腾cpu K1-930 intel 安腾cpu K1-910 intel 安腾cpu K1-800 intel 志强cpu ...
- 集群环境下,Session管理的几种手段
集群环境下,Session管理的几种手段 1.Session复制 缺点:集群服务器间需要大量的通信进行Session复制,占用服务器和网络的大量资源. 由于所有用户的Session信息在每台服务器上都 ...
- jsp输出九九乘法表
<% String st = ""; for(int i = 1; i <= 9; i++){ for(int j = 1; j <= i; j++){ st + ...
- XML与Plist文件转换
由于工作需要,要解析xml,举一个简单的例子,例如地址,如果是plist的话我们会很好的解析,但是如果已知一个xml的话,当然用原生的xml解析也能解析的出来,但是解析xml的话会是根据标签的头来解析 ...
- sql中--行处理数据的两种方式
--创建待使用的表格CREATE TABLE Orders ( OrderID INT , CostValue DECIMAL(18, 2) );WITH cte_temp AS ( SELECT 1 ...