ControlValueAccessor 是什么?

简单来说ControlValueAccessor是一个接口,它被用于在 Angular 的 FormControl 实例和原生 DOM 元素之间创建一个桥梁。其使用方式和OnInit类似,需要程序员在自定义组件里面实现相应的方法。

import {
ControlValueAccessor,
NG_VALUE_ACCESSOR
} from '@angular/forms';@Component({selector: 'custom',templateUrl: './custom.component.html',styleUrls: ['./custom.component.less'],providers: [     {provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => CustomComponent),multi: true     }   ]
})
export class CustomComponent implements ControlValueAccessor, OnInit, {…

为什么需要使用 ControlValueAccessor

有时,你可能需要创建自定义的表单元素,并希望它能和Angular的FormControl成功通信。这时你便需要ControlValueAccessor来实现这个目的。

比如:

this.myForm = new FormGroup({userName: new FormControl({value: '', disabled: false})
});
<form [formGroup]="myForm" (ngSubmit)="onSubmit()"><div class="form-group"><label>Name:<my-input formControlName="userName"></my-input></label></div><div class="form-group"><button type="submit">Submit</button></div>
</form>

深入理解

ControlValueAccessor的使用方法在Angular官网和很多的文章中都有介绍,但是它具体是如何起作用的呢?

Angular 需要一种通用机制来桥接原生/自定义表单控件和 formControl 指令,而这正是 ControlValueAccessor 干的事情。这个对象桥接原生表单控件和 formControl 指令,并同步两者的值。任何一个组件或指令都可以通过实现 ControlValueAccessor 接口并注册为 NG_VALUE_ACCESSOR,从而转变成 ControlValueAccessor 类型的对象。

其实原生表单控件也拥有类似于ControlValueAccessor的接口,比如:当 Angular 在组件模板中中遇到 input 或 textarea DOM 原生控件时,就会使用DefaultValueAccessor 指令

Accessor

Form Element

DefaultValueAccessor

input,textarea

CheckboxControlValueAccessor

input[type=checkbox]

NumberValueAccessor

input[type=number]

RadioControlValueAccessor

input[type=radio]

RangeValueAccessor

input[type=range]

SelectControlValueAccessor

select

SelectMultipleControlValueAccessor

select[multiple]

以上是Angular 为所有原生 DOM 表单元素创建的 Angular 表单控件,即内置ControlValueAccessor

ControlValueAccessor 接口定义了四个方法:

- writeValue(obj:any):将表单模型中的新值写入视图或DOM属性(如果需要)的方法,它将来自外部的数据写入到内部的数据模型。

- registerOnChange(fn:any):一种注册处理程序的方法,当视图中的某些内容发生更改时应调用该处理程序。它具有一个告诉其他表单指令和表单控件以更新其值的函数。通常在 registerOnChange 中需要保存该事件触发函数,在数据改变的时候,可以通过调用事件触发函数通知外部数据变了,同时可以将修改后的数据作为参数传递出去。

- registerOnTouched(fn: any):注册 onTouched 事件,基本同 registerOnChange ,只是该函数用于通知表单组件已经处于 touched 状态,改变绑定的 FormControl 的内部状态。

- setDisabledState(isDisabled: boolean):当调用 FormControl 变更状态的 API 时得表单状态变为 Disabled 时调用 setDisabledState() 方法,以通知自定义表单组件当前表单的读写状态。

formControl 指令使用 writeValue 方法设置原生表单控件的值;使用 registerOnChange 方法来注册由每次原生表单控件值更新时触发的回调函数,我们需要把更新的值传给这个回调函数,这样对应的 Angular 表单控件值也会更新;使用 registerOnTouched 方法来注册用户和控件交互时触发的回调。

formControl会调用名为setUpControl的函数,ControlValueAccessor的实例valueAccessor会被作为参数传入这个函数中。在setUpControl中,ControlValueAccessor的四个方法会在交互时被调用,以完成formControl和元素之间的通信。

拓展:

在使用ControlValueAccessor时需要一同引入NG_VALUE_ACCESSOR,它是使用InjectionToken 创建的可在 Provider 中使用的 Token。我们在编写自己的项目时一般不需要用到InjectionToken,但是在一个框架或者第三方的插件中,它就变得十分有必要了。

export const NG_VALUE_ACCESSOR =new InjectionToken<ReadonlyArray<ControlValueAccessor>>('NgValueAccessor');

试想当我使用依赖注入的功能时,我需要将我创建的依赖注册进组件中。这时我就需要一个令牌,如果我使用一个字符串作为令牌就有可能会造成重复,相同的令牌会导致后面的覆盖前面的。所以需要一个Token作为一个唯一值来防止这种冲突。

providers: [{ provide: TOKEN, useValue: … }]

Angular 组件接口之 ControlValueAccessor相关推荐

  1. Angular 组件交互

    Angular 组件交互 组件交互: 组件通讯,让两个或多个组件之间共享信息. 使用场景: 当某个功能在多个组件中被使用到时,可以将该特定的功能封装在一个子组件中,在子组件中处理特定的任务或工作流. ...

  2. 组件接口(API)设计指南-文件夹

    组件接口(API)设计指南-文件夹 组件接口(API)设计指南[1]-要考虑的问题 组件接口(API)设计指南[2]-类接口(class interface) 组件接口(API)设计指南[3]-托付( ...

  3. angular input_快速地上手Angular组件开发

    如果我会一些Javascript的基础知识,我可以快速地上手Angular吗?或者说,我是一名前端工作者,没有接触过Angular,我该如何快速地使用Angular进行日常开发呢?我是轻流前端团队的一 ...

  4. Angular Elements,四步将Angular 组件转换为 web 组件

    Angular Elements,四步将Angular 组件转换为 web 组件 从Angular版本6开始,我们可以将Angular组件公开为Web组件,或者更确切地说:作为自定义元素,它是Web组 ...

  5. pb怎么封装com组件_从零开始构建 Angular 组件库

    NG-ZORRO 组件库官网地址:Ant Design Of Angular Github地址:NG-ZORRO/ng-zorro-antd 更新:视频已上传 谢亚东演讲视频_腾讯视频​v.qq.co ...

  6. 使用NG-ZORRO(Angular 组件库)中Table组件,通过columnTable属性固定列,结果每行数据内容穿透了两遍的固定列;鼠标滑过该条数据时,两侧固定列的背景色不跟着改变~

    [问题] 使用NG-ZORRO(Angular 组件库)中Table组件,通过#columnTable属性固定列,结果每行数据内容穿透了两遍的固定列(因为是刚开始做这个项目,所以盲猜是之前某位同仁搞个 ...

  7. angular 设置接口调用地址_[译] 关于 Angular 的变化检测,你需要知道的一切

    原文地址:Everything you need to know about change detection in Angular 原文作者:Max, Wizard of the Web 译文出自: ...

  8. elementui的tree组件页面显示不出数据_[Angular 组件库NG-ZORRO基础入门] -Hacker News: Pagination...

    前言回顾 到目前为止,我们已经实现了 hacker news 大部分页面功能设计,但是仍然缺少一个重要的翻页功能,API 现在没人是返回 20 条数据,我们今天会使用 Pagination 组件 将分 ...

  9. Angular组件——投影

    运行时动态改变组件模版的内容.没路由那么复杂,只是一段html,没有业务逻辑. ngContent指令将父组件模版上的任意片段投影到子组件上. 一.简单例子 1.子组件中使用<ng-conten ...

最新文章

  1. IIS Express总结
  2. 大数据技术 学习之旅_数据-数据科学之旅的起点
  3. tcp 测试软件,ztcp
  4. Linux内核中的常用宏container_of其实很简单【转】
  5. 创造性模式——原型模式
  6. keepalived java,keepalived 安装及使用
  7. Corel Painter 2022 for Mac(初学者可驾驭的绘画软件)
  8. Smobiler中Poplist控件的用法
  9. Excel读取mysql数据库
  10. 向量积的坐标运算公式推导_向量积的坐标运及度量公式.ppt
  11. 圆周率在java中的标识符_java 圆周率。
  12. 王森:程序设计师真情忏悔录
  13. 在线社交网络分析 github,在线社交网络分析软件
  14. already opened by ClassLoader
  15. FA-PEG-SH 叶酸PEG巯基
  16. R语言-南丁格尔玫瑰图
  17. 标梵分享微信官方账号运营推广思路
  18. TCP/IP协议、请求报文和响应报文
  19. 卷积核——Roberts、Prewitt、Sobel、Lapacian、DoG、LoG算子
  20. 模拟集成电路设计与分析——全差分放大器

热门文章

  1. Postman进阶篇(十二)-在脚本中使用pm对象访问接口响应数据(pm.response.*)
  2. 遗传算法混流装配线平衡毕业论文【matlab/Flexsim仿真】
  3. 用这个来代替 mail 。。更爽~
  4. 无方向盘!通用汽车宣布2019年生产无人驾驶汽车 | 消息
  5. 达梦DSC集群的备份与还原
  6. 简单的服务调用框架实现
  7. 复现:A Graph-Based Approach for Active Learning in Regression
  8. 火影忍者手游打秘境服务器响应超时,火影忍者打秘境版本号不一致什么情况 | 手游网游页游攻略大全...
  9. 企业舆情监控排查什么,TOOM讲解企业舆情监控工作方案?
  10. java操作derby_javaDB—— derby简单操作