在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双向数据绑定的更多相关文章

  1. angular学习笔记(四)- input元素的ng-model属性

    input元素的ng-model属性: 用于将input的值和变量的值进行双向绑定 <!DOCTYPE html> <html ng-app> <head> < ...

  2. 前端 | 自定义组件 v-model:Vue 如何实现双向绑定

    v-model 是 Vue 中一个常用的指令,常用于表单中的数据绑定.如下基本用法想必大家都很熟悉,data 中的 checked 属性的值就会随着多选框的状态实时变化. <el-checkbo ...

  3. 【vue】---- v-model在自定义组件中的使用

    1. v-model简介 可以用 v-model 指令在表单 <input>.<textarea> 及 <select> 元素上创建双向数据绑定,它的本质是一个语法 ...

  4. 组件使用v-model、$listeners、.sync(区别于v-model的双向数据绑定)

    自定义组件 自定义组件的v-model 首先我们先说一下在自定义组件中使用v-model的必要条件 在自定义的组件中要有input(这里我们先不讨论单选复选框) 在自定义组件的模板对象中要有props ...

  5. ionic3+angular4开发混合app 之自定义组件

    这里主要是记录ionic3+angular4开发混合app时自定义组件,我想自定义组件的方法和angular4应该类似,具体在纯angular4中自定义组件,暂时没有实践,个人觉得差别不大,之后实践了 ...

  6. ionic3.x angular4.x ng4.x 自定义组件component双向绑定之自定义计数器

    本文主要示例在ionic3.x环境下实现一个自定义计数器,实现后最终效果如图: 1.使用命令创建一个component ionic g component CounterInput 类似的命令还有: ...

  7. 玩转angularJs——通过自定义ng-model,不仅仅只是input可以实现双向数据绑定

    体验更优排版请移步原文:http://blog.kwin.wang/programming/angularJs-user-defined-ngmodel.html angularJs双向绑定特性在开发 ...

  8. vue input框type=number 保留两位小数自定义组件

    第一步:自定义组件MyNumberInput.vue<template> <input class="numberInput" type="number ...

  9. angular4 自定义表单组件

    自定义表单组件分为单值组件和多值组件. 单值组件:input/select/radio/textarea 多值组件:checkbox/tree组件 条件: 1.必须实现ControlValueAcce ...

随机推荐

  1. JS 去除字符串中的最后一个字符

    var str = 'Hello World!'; str = str.substr(0,str.length-1); alert(str);

  2. 小米净水器与小区过滤价格水对照.xls

    总结:要是一天用水量为7升下面.还是用小区的过滤水为好,合算. 假设过滤水需求量大,可能小米的净水器比較好.当然,小区的要天天去接.要求风雨无阻的. 这点小米的随用随接就更好. 注意一点,小米的还要用 ...

  3. less05 作用域

    less @clolor:#ffffff; .bgcolor{ width: 50px; a{ color: @clolor; } @clolor:#ff0000; //覆盖,作用域跟js一样,现在局 ...

  4. bzoj1070: [SCOI2007]修车(费用流)

    1070: [SCOI2007]修车 题目:传送门 题解: 一道挺简单的费用流吧...胡乱建模走起 贴个代码... #include<cstdio> #include<cstring ...

  5. vs输出窗口,显示build的时间

    https://stackoverflow.com/questions/82128/displaying-build-times-in-visual-studio Tools... Options.. ...

  6. Find or Query Data with C# Driver

    https://docs.mongodb.com/getting-started/csharp/query/ Overview You can use the Find and FindAsync m ...

  7. pandas dataframe 做机器学习训练数据=》直接使用iloc或者as_matrix即可

    样本示意,为kdd99数据源: 0,udp,private,SF,105,146,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0.00,0.00,0.00,0.00,1.0 ...

  8. C# 蚁群优化算法实现

    C# 蚁群优化算法实现 需求为(自己编的,非实际项目): 某配送中心进行揽货,目标客户数为50个客户,配送中心目前的运力资源如下: 现有车辆5台 单台运力最大行驶距离200千米 单台运力最大载重公斤1 ...

  9. [HNOI2012] 永无乡 解题报告 (splay+启发式合并)

    题目链接:https://www.luogu.org/problemnew/show/P3224#sub 题目: 题目大意: 维护多个联通块,没有删除操作,每次询问某一联通块的第k大 解法: 维护联通 ...

  10. BZOJ 1391 网络流

    vis[0]没有清零查一年- //By SiriusRen #include <cstdio> #include <cstring> #include <algorith ...