详解Angular中实现自定义组件的双向绑定的两种方法


Posted in Javascript onNovember 23, 2018

在 Angular 中,对于表单元素,通过 [(ngModel)] 即可以简单地实现双向绑定。对于自定义组件而言,希望实现同样的效果可以怎么做呢?

1 实现自定义组件的 ngModel 指令

如果希望自定义组件能够具有与表单元素相同的 ngModel 效果,可以通过在组件内实现 ControlValueAccessor 接口达到目的。

对于 [(ngModel)] ,需要至少实现该接口的如下方法:

interface ControlValueAccessor { 
 writeValue(obj: any): void
 registerOnChange(fn: any): void
 registerOnTouched(fn: any): void
}

最简单的核心实现示例参考如下。

import { ControlValueAccessor } from '@angular/forms/src/directives';
import { Component, forwardRef, Input } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';

@Component({
 selector: 'custom-input',
 template: `<input [(ngModel)]="value"/>`,
 providers: [
  {
   provide: NG_VALUE_ACCESSOR,
   useExisting: forwardRef(() => UnionInputComponent),
   multi: true
  }
 ]
})
export class CustomInputComponent implements ControlValueAccessor {
 constructor() { }
 private innerValue: any = '';
 private onTouchedCallback: () => void = function () { };
 private onChangeCallback: (_: any) => void = function () { };

 get value(): any {
  return this.innerValue;
 }
 set value(v: any) {
  if (v !== this.innerValue) {
   this.innerValue = v;
   this.onChangeCallback(v);
  }
 }
 /**
  * model view -> view value
  */
 writeValue(value: any) {
  if (value !== this.innerValue) {
   this.innerValue = value;
  }
 }
 /**
  * view value ->model value
  */
 registerOnChange(fn: any) {
  this.onChangeCallback = fn;
 }
 registerOnTouched(fn: any) {
  this.onTouchedCallback = fn;
 }
}

2 使用 get/set 关键字实现父子组件的双向绑定

其实实现双向绑定内部的本质原理就是父子组件的事件绑定机制。简单举例如下。

2.1 自定义子组件定义

import { Input, Output, Component, EventEmitter } from '@angular/core';

@Component({
 selector: 'custom-input',
 template: `<input [(ngModel)]="innerValue"/>`,
})
export class CustomInputComponent {
 innerValue;

 @Input()
 get twoWayModel() {
  return this.innerValue;
 }
 set twoWayModel(val) {
  this.innerValue = val;
  this.twoWayModelChange.emit(this.innerValue);
 }
 @Output() twoWayModelChange: EventEmitter<string> = new EventEmitter</string><string>();
}

2.2 使用自定义组件

在需要使用组件的地方,通过 [(twoWayModel)] 即可实现双向绑定的效果。

import { Input, Output } from '@angular/core';
import { Component, forwardRef, Input } from '@angular/core';
@Component({
 selector: 'custom-input',
 template: `<custom -input [(twoWayModel)]="inputValue" (twoWayModelChange)="onInputValueChange($event)"></custom>`
})
export class abcComponent {
 inputValue;
 onInputValueChange(val) {
  console.log(val);
  console.log(val === this.inputValue); // true
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript 拖拉缩放效果
Dec 10 Javascript
FireFox JavaScript全局Event对象
Jun 14 Javascript
AngularJS基础学习笔记之指令
May 10 Javascript
js运动应用实例解析
Dec 28 Javascript
基于JavaScript实现移除(删除)数组中指定元素
Jan 04 Javascript
javascript实现九宫格相加数值相等
May 28 Javascript
从零学习node.js之文件操作(三)
Feb 21 Javascript
JS如何判断浏览器类型和详细区分IE各版本浏览器
Mar 04 Javascript
Angular之toDoList的实现代码示例
Dec 02 Javascript
vue通过video.js解决m3u8视频播放格式的方法
Jul 30 Javascript
no-vnc和node.js实现web远程桌面的完整步骤
Aug 11 Javascript
vue基本使用--refs获取组件或元素的实例
Nov 07 Javascript
Vue.js组件间通信方式总结【推荐】
Nov 23 #Javascript
vue-cli 2.*中导入公共less文件的方法步骤
Nov 22 #Javascript
vue全局使用axios的方法实例详解
Nov 22 #Javascript
vue中的ref和$refs的使用
Nov 22 #Javascript
浅析vue 函数配置项watch及函数 $watch 源码分享
Nov 22 #Javascript
原生JS实现手动轮播图效果实例代码
Nov 22 #Javascript
js实现按钮开关单机下拉菜单效果
Nov 22 #Javascript
You might like
MySQL授权问题总结
2007/05/06 PHP
彻底杜绝PHP的session cookie错误
2009/08/09 PHP
WordPress中制作导航菜单的PHP核心方法讲解
2015/12/11 PHP
PHP工程师VIM配置分享
2015/12/15 PHP
浅谈PHP定义命令空间的几个注意点(推荐)
2016/10/29 PHP
基于Jquery的淡入淡出的特效基础练习
2010/12/13 Javascript
获取下拉列表框的值是数组,split,$.inArray示例
2013/11/13 Javascript
javascript实现动态侧边栏代码
2014/02/19 Javascript
jquery幻灯片插件bxslider样式改进实例
2014/10/15 Javascript
JavaScript弹出新窗口并控制窗口移动到指定位置的方法
2015/04/06 Javascript
JavaScript 轮播图和自定义滚动条配合鼠标滚轮分享代码贴
2016/10/28 Javascript
详解springmvc 接收json对象的两种方式
2016/12/06 Javascript
JS实现一次性弹窗的方法【刷新后不弹出】
2016/12/26 Javascript
jQuery动态追加页面数据以及事件委托详解
2017/05/06 jQuery
通过构造函数实例化对象的方法
2017/06/28 Javascript
解决webpack -p压缩打包react报语法错误的方法
2017/07/03 Javascript
Grunt针对静态文件的压缩,版本控制打包的实例讲解
2017/09/29 Javascript
详解Vue用cmd创建项目
2019/02/12 Javascript
使用layer弹窗提交表单时判断表单是否输入为空的例子
2019/09/26 Javascript
jQuery实现图片切换效果
2020/10/19 jQuery
vue3.0中友好使用antdv示例详解
2021/01/05 Vue.js
python3使用urllib示例取googletranslate(谷歌翻译)
2014/01/23 Python
Python动态导入模块的方法实例分析
2018/06/28 Python
Python实现的json文件读取及中文乱码显示问题解决方法
2018/08/06 Python
python实现彩票系统
2020/06/28 Python
python文件拆分与重组实例
2018/12/10 Python
docker django无法访问redis容器的解决方法
2019/08/21 Python
opencv 图像腐蚀和图像膨胀的实现
2020/07/07 Python
CSS3 文字动画效果
2020/11/12 HTML / CSS
html5基础标签(html5视频标签 html5新标签用法)
2013/12/30 HTML / CSS
夜大毕业自我鉴定
2013/10/11 职场文书
高中生家长会演讲稿
2014/01/14 职场文书
教师自查自纠材料
2014/10/14 职场文书
大学优秀学生主要事迹材料
2015/11/04 职场文书
个人房屋租赁合同(标准范本)
2019/09/16 职场文书
Windows 64位 安装 mysql 8.0.28 图文教程
2022/04/19 MySQL