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. matlab图形绘制经典案例,MATLAB经典教程第四章_图形绘制.ppt
  2. 白大脑比超级计算机还,和超级计算机相比,人类的大脑很弱吗
  3. java获取jsp_JSP、JAVA获取各种路径总结
  4. JVM编译时和运行时状态
  5. Swift开发:NSLayoutConstraint纯代码实现自动布局-初级篇
  6. Linux命令【五】系统函数
  7. mysql极客_极客mysql16
  8. 整数大小比较(信息学奥赛一本通-T1043)
  9. 论开心网和人人网的衰落
  10. dcp9030cdn定影_兄弟DCP-9030CDN驱动
  11. PS使用技巧(一) 移动工具 V
  12. 贝叶斯分类器,什么是朴素贝叶斯,后续为使用贝叶斯实现海量数据的邮件筛选。带源码数据集和解决思路
  13. 科学计算机后盖换电池,图吧小白教程 篇二十二:手把手教你给手机换电池(拆机)...
  14. python绘制的Svg图打开一片空白
  15. (23)Linux基础-系统磁盘阵列raid
  16. 物联卡一直显示待激活怎么办_物联卡开始要求活体认证,这种纯流量卡你以后还管乱使用吗?...
  17. 【电机/控制理论】DTC(Direct Torque Control)直接转矩控制
  18. .Net Core通过NPOI在CentOS 7(Docker)环境中导出Excel报错The type initializer for ‘Gdip‘ 的问题
  19. 产品三大文档BRD/MRD/PRD
  20. 食品行业质量追溯系统的建设(一)

热门文章

  1. 完整代码\nmyopenglwidget
  2. 强壮的ZZW (一维dp 01背包)
  3. Excel将单表复制追加到另一个未打开的工作簿
  4. 2017战略No.1:坚定不移地走全产业链发展路线
  5. simple note
  6. 直接用mathtype将公式转换为latex格式
  7. 机器学习——KNN(K-nearst Neighbor)
  8. 计算地址线数据线的方法
  9. JavaScript 多维数组
  10. 扫描点读笔搭载北京君正X2000多核异构跨界处理器的案例