详解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 相关文章推荐
Extjs学习笔记之三 extjs form更多的表单项
Jan 07 Javascript
IE8 chrome中table隔行换色解决办法
Jul 09 Javascript
JavaScript中判断函数是new还是()调用的区别说明
Apr 07 Javascript
js实现仿阿里巴巴城市选择框效果实例
Jun 24 Javascript
深入理解js函数的作用域与this指向
May 28 Javascript
Angular.js去除页面中显示的空行方法示例
Mar 30 Javascript
bootstrap如何让dropdown menu按钮式下拉框长度一致
Apr 10 Javascript
Vue基于NUXT的SSR详解
Oct 24 Javascript
微信小程序调用摄像头隐藏式拍照功能
Aug 22 Javascript
Vue-不允许嵌套式的渲染方法
Sep 13 Javascript
微信小程序用canvas画图并分享
Mar 09 Javascript
vue组件的路由高亮问题解决方法
May 11 Vue.js
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
PHP实现获取FLV文件的时间
2015/02/10 PHP
Linux系统下php获得系统分区信息的方法
2015/03/30 PHP
php中strlen和mb_strlen用法实例分析
2016/11/12 PHP
php 函数使用可变数量的参数方法
2017/05/02 PHP
node.js应用后台守护进程管理器Forever安装和使用实例
2014/06/01 Javascript
jQuery中attr()方法用法实例
2015/01/05 Javascript
jQuery选择器querySelector的使用指南
2015/01/23 Javascript
JavaScript闭包详解
2015/02/02 Javascript
使用jQuery获得内容以及内容的属性
2015/02/26 Javascript
基于Arcgis for javascript实现百度地图ABCD marker的效果
2015/09/12 Javascript
微信小程序 devtool隐藏的秘密
2017/01/21 Javascript
xmlplus组件设计系列之路由(ViewStack)(7)
2017/05/02 Javascript
详解Node.js项目APM监控之New Relic
2017/05/12 Javascript
AngularJS 异步解决实现方法
2017/06/12 Javascript
解决npm安装Electron缓慢网络超时导致失败的问题
2018/02/06 Javascript
JS实现判断图片是否加载完成的方法分析
2018/07/31 Javascript
解决vue同一slot在组件中渲染多次的问题
2018/09/06 Javascript
js使用formData实现批量上传
2020/03/27 Javascript
微信小程序HTTP接口请求封装的实现
2019/02/21 Javascript
fastadmin中调用js的方法
2019/05/14 Javascript
js实现一个简易计算器
2020/03/30 Javascript
JS一次前端面试经历记录
2020/03/19 Javascript
vue 解决mintui弹窗弹起来,底部页面滚动bug问题
2020/11/12 Javascript
python使用socket连接远程服务器的方法
2015/04/29 Python
python enumerate函数的使用方法总结
2017/11/15 Python
用python3教你任意Html主内容提取功能
2018/11/05 Python
python openpyxl使用方法详解
2019/07/18 Python
Pycharm 2020年最新激活码(亲测有效)
2020/09/18 Python
Python监听剪切板实现方法代码实例
2020/11/11 Python
分享29个基于Bootstrap的HTML5响应式网页设计模板
2015/11/19 HTML / CSS
ECCO爱步美国官网:来自丹麦的鞋履品牌
2016/11/23 全球购物
英国莱斯特松木橡木家具网上商店:Choice Furniture Superstore
2019/07/05 全球购物
投标人廉洁自律承诺书
2014/05/26 职场文书
纺织工程专业推荐信
2014/09/08 职场文书
工作失职自我检讨书
2015/05/05 职场文书
创业计划书之面包店
2019/09/12 职场文书