本文简单介绍封装使用ngModel
实现自定义表单控件的过程。
NgModel 相关
NgModel
NgModel
用于从作用域创建一个FormControl
实例,并将它绑定到一个表单控件元素。
ngModel
继承自NgControl
NgControl
NgControl
是所有控制指令继承的基础类。它将一个FormControl
绑定到DOM元素中。
FormControl
、FormGroup
、FormArray
,三者都用于angular表单的值和状态的跟踪,区别是一个控件、一组控件或者是它们的组合。
FormControl
用于跟踪一个单独的表单控件的值和有效性状态。它对应一个HTML表单控件,不如输入框和下拉框。 FormGroup
用于跟踪一组AbstractControl
的实例的值和有效性状态。该组的属性中包含了它的子控件。组件中的顶级表单就是一个FormGroup
。 FormArray
用于跟踪AbstractControl
实例组成的有序数组的值和有效性状态。
ControlValueAccessor
ControlValueAccessor
用于在控制和原生元素之间建立联系,它封装了赋值到一个表现为input
元素的DOM元素。
简单说,就是angular中的input是带有[(ngModel)]
这个属性的,而我们想要自己控制这个input
的写入过程,使用ControlValueAccessor
就可以做到。
ControlValueAccessor
提供以下接口:
writeValue(obj: any) : void:
写入值到元素registerOnChange(fn: any) : void:
设置当控件接收到change事件时触发的回调registerOnTouched(fn: any) : void:
设置当控件接收到touch事件时触发的回调setDisabledState(isDisabled: boolean) : void:
该函数将在控件状态或者disabled
值变化,根据值来对元素启用或失效
DefaultValueAccessor
DefaultValueAccessor
提供值写入和监听变化的默认访问,像NgModel
, FormControlDirective
, 和FormControlName
指令会使用。
DefaultValueAccessor
提供类包括:
onChange : (_: any) => {}
change事件变化监听onTouched : () => {}
touch事件变化监听
以及ControlValueAccessor
(上面)的接口。
NG_VALUE_ACCESSOR
NG_VALUE_ACCESSOR
提供一个ControlValueAccessor
供表单控制使用。
创建自定义input控件
我们想要封装后的组件跟原生的angular组件一样,像表现为input的自定义控件,我们想要使用[(ngModel)]
来进行双向绑定,我们需要使用ControlValueAccessor
来拓展。
而这里ControlValueAccessor
只是一个接口,我们应用它,还需要获取一些可用的服务,这时候需要注入NG_VALUE_ACCESSOR
。
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => CustomInputComponent), multi: true};复制代码
这里简单讲讲几个概念:
- 我们自定义了一个访问控制服务,该服务包装为
NG_VALUE_ACCESSOR
服务,主要用于控制ControlValueAccessor
相关的访问。 - 我们需要将自定义input控件提供给
NG_VALUE_ACCESSOR
,以便通过自定义方式控制父组件的[(ngModel)]
以及其他表单相关的访问。 forwardRef
用于将目前还未获取到的依赖关联起来,这里我们关联后面的自定义Input组件。
@Component({ selector: 'app-custom-input', templateUrl: './custom-input.component.html', styleUrls: ['./custom-input.component.css'], providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => CustomInputComponent), multi: true } ]})export class CustomInputComponent implements OnInit, ControlValueAccessor { /* * 自定义表单控件 * 需要完成ControlValueAccessor内部的方法 * */ private _custom: any = ''; // 定义ControlValueAccessor提供的事件回调 private onChange = (_: any) => { }; get custom(): any { return this._custom; } set custom(v: any) { if (v !== this._custom) { this._custom = v; this.onChange(this._custom); } } constructor() { } ngOnInit() { } writeValue(val: any): void { this._custom = val; } registerOnChange(fn: any): void { this.onChange = fn; } registerOnTouched(fn: any): void { }}复制代码
具体的实现实例参考