So when you need to create a ControlValueAccessor?

When you want to use a custom component as form control. For example a counter component, you can custom the style and the way to control the value changes.

It needs some setup for control value accessor, but after you have done it once, you can prettty much just copy & paste the same template around to create a control value access.

import { Component, Input, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; const COUNTER_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => StockCounterComponent),
multi: true
}; @Component({
selector: 'stock-counter',
providers: [COUNTER_VALUE_ACCESSOR],
styleUrls: ['stock-counter.component.scss'],
template: `
...
`
})
export class StockCounterComponent implements ControlValueAccessor { value: number; writeValue(val: number) {
this.value = val;
} registerOnChange(fn: any) {
this.onModelChange = fn;
} registerOnTouched(fn: any) {
this.onTouch = fn;
} ...
}

So the template is somehow like the code above, highly recommend to create any snippet or live template in your IDE.

So inside the component we create, we have three methods,

  • writeValue(obj: any)
  • registerOnChange(fn: Function)
  • registerOnTouched(fn: Function)

To understand each method is the key point to understand how control value access.

So first 'writeValue':

  value: number;

  writeValue(val: number) {
this.value = val;
}

This is for setting initial value, we take value from our form builder and pass to our component via 'writeValue'.

        <stock-counter
[step]=""
[min]=""
[max]=""
formControlName="quantity">

So the value comes from 'formControlName="quantity"'.

Now at the point, you can think that our form holds a model value and our component also holds a view value.

We need to sync model value and view value.

The way to do that is by "registerOnChange":

  registerOnChange(fn: any) {
this.onModelChange = fn;
}
  increment() {
this.value = this.value === this.max ?
this.value :
this.value + this.step; this.onModelChange(this.value); }

Every time our view value (component value) changed, to need to notify our form about the changes, we need to call 'this.onModelChange(this.value)' function and pass in the changes value.

After this form will be able to the updated value.

OK, now we able to sync the value from our component to our form. But you might think about this can be easily done by EventEmitter, when border to create Control value accessor? The most important reason is that "Validation"!

html "form" component actually does lots of thing underhook. What example, it set field state "untouch", "touched", "dirty", "prinstin". We use those status to do validation and error messages.

For example:

input.ng-touched.ng-invalid {
border-left: 5px solid red;
}

If the field is touched and is invalid, we set the border to red.

Currently, we have our value synced, and control value access also helps us to add form validation ability to our component. But once the value changed, our component still show 'ng-untouch':

So we need "registerOnTouched" function to help us to do that:

  registerOnTouched(fn: any) {
this.onTouch = fn;
}
  increment() {
this.value = this.value === this.max ?
this.value :
this.value + this.step; this.onModelChange(this.value);
this.onTouch();
}

Now after the value changed, our component will be set 'ng-touched', now we are fully conver our component to a form component.

Code

[Angular] Implementing a ControlValueAccessor的更多相关文章

  1. [Angular] Implementing A General Communication Mechanism For Directive Interaction

    We have modal implement and now we want to implement close functionality. Becuase we use a structure ...

  2. [Angular] Create a ng-true-value and ng-false-value in Angular by controlValueAccessor

    If you're coming from AngularJS (v1.x) you probably remember the ng-true-value and ng-false-value di ...

  3. Angular写一个Form组件-TagInput

    前端开发少不了和表单打交道; Angular中, 提供了强大的表单的支持, 响应式表单(Reactive Form) 和 模板驱动的表单(Template-driven Form) 的双向数据流给我们 ...

  4. Angular Forms - 自定义 ngModel 绑定值的方式

    在 Angular 应用中,我们有两种方式来实现表单绑定--"模板驱动表单"与"响应式表单".这两种方式通常能够很好的处理大部分的情况,但是对于一些特殊的表单控 ...

  5. angular实现简单的pagination分页组件

    不想使用第三方库,只想使用一个分页器,那么就简单的实现一个,效果如下: 1.使用方式: <custom-pagination *ngIf="enterpriseList.length& ...

  6. [AngularFire] Angular File Uploads to Firebase Storage with Angular control value accessor

    The upload class will be used in the service layer. Notice it has a constructor for file attribute, ...

  7. [Angular] Implement a custom form component by using control value accessor

    We have a form component: <label> <h3>Type</h3> <workout-type formControlName=& ...

  8. angular 响应式自定义表单控件—注册头像实例

    1. 组件继承ControlValueAccessor,ControlValueAccessor接口需要实现三个必选方法 writeValue() 用于向元素中写入值,获取表单的元素的元素值 regi ...

  9. 表单-angular

    模板表单: <form #myform="ngForm" (ngSubmit)="onsubmit(myform.value)" > <div ...

随机推荐

  1. BZOJ2631: tree(LCT)

    Description 一棵n个点的树,每个点的初始权值为1.对于这棵树有q个操作,每个操作为以下四种操作之一: + u v c:将u到v的路径上的点的权值都加上自然数c: - u1 v1 u2 v2 ...

  2. bzoj3307雨天的尾巴(权值线段树合并/DSU on tree)

    题目大意: 一颗树,想要在树链上添加同一物品,问最后每个点上哪个物品最多. 解题思路: 1.线段树合并 假如说物品数量少到可以暴力添加,且树点极少,我们怎么做. 首先在一个树节点上标记出哪些物品有多少 ...

  3. 【Educational Codeforces Round 35 D】Inversion Counting

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 排列中交换任意两个数字. 排列的逆序对个数的奇偶性会发生变化. 翻转这个过程其实就是len/2对数字发生交换. 交换了偶数次的话,不 ...

  4. 洛谷 P2067 Cytus-Holyknight

    P2067 Cytus-Holyknight 题目背景 本人最初作 以此纪念伟大的ios.安卓.PSV平台音乐游戏<cytus> 后续将不断更新. -------------Chapter ...

  5. 设计模式之十二:状态模式(State)

    状态模式: 当一个对象的内部状态发生变化时同意改变它的行为. Allow an object to alter its behavior when its internal state changes ...

  6. springMVC视图解析器——InternalResourceViewResolver(转)

    springmvc在处理器方法中通常返回的是逻辑视图,如何定位到真正的页面,就需要通过视图解析器. springmvc里提供了多个视图解析器,InternalResourceViewResolver就 ...

  7. 如何把excel同一个单元格内的文字和数字分别提取出来?

    平台:excel 2010 目的:把excel同一个单元格内的文字和数字分别提取出来 操作: 假设数据在A1单元格:如果文字在前,B1=left(A1,lenb(A1)-len(A1))可得文字,C1 ...

  8. 记一些stl的用法(持续更新)

    有些stl不常用真的会忘qwq,不如在这里记下来,以后常来看看 C++中substr函数的用法 #include<string> #include<iostream> usin ...

  9. 【Educational Codeforces Round 33 A】Chess For Three

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 模拟题.知道哪个人是旁观者就好 [代码] /* 1.Shoud it use long long ? 2.Have you ever ...

  10. Android中的Parcelable接口和Serializable使用方法和差别

    Parcelable接口: Interface for classes whose instances can be written to and restored from a Parcel. Cl ...