Angular学习之ControlValueAccessor接口详解
1. ControlValueAccessor介绍
ControlValueAccessor是Angular提供的一个接口,主要用于实现可自定义双向数据绑定的表单控件。在Angular中,几乎所有的表单控件都实现了ControlValueAccessor接口,包括常见的input、select、textarea等。
1.1 ControlValueAccessor接口的作用
ControlValueAccessor接口的作用是将模型值的写入与控件值的呈现分离开来。这使得我们可以将同样的控制逻辑应用于不同的表单控件。
同时,ControlValueAccessor还具有双向数据绑定的能力。通过ControlValueAccessor,我们可以将控件值的变化自动同步到模型中,同时也可以将模型的变化自动更新到控件中。
1.2 ControlValueAccessor接口的核心方法
ControlValueAccessor接口包含以下核心方法:
1. writeValue(obj: any): void //将模型值写入到控件中
2. registerOnChange(fn: any): void //在控件值发生变化时,调用模型中注册的回调函数
3. registerOnTouched(fn: any): void //在控件失去焦点时,调用模型中注册的回调函数
4. setDisabledState(isDisabled: boolean): void //设置控件的禁用状态
2. 实现ControlValueAccessor接口
2.1 实现ControlValueAccessor接口的必要条件
要实现ControlValueAccessor接口,必须满足以下条件之一:
1. 继承自ControlValueAccessor类
2. 具有形如NG_VALUE_ACCESSOR的InjectionToken注入标识符
2.2 实现ControlValueAccessor接口的步骤
实现ControlValueAccessor接口需要完成以下步骤:
1. 实现接口
2. 注册实现类
3. 在组件中使用自定义表单控件
下面,我们通过一个示例来演示实现ControlValueAccessor接口的过程。
3. 示例
示例中,我们将实现一个自定义的星级评分控件,它能够实现双向数据绑定,并且可以禁用控件。
首先,我们需要创建一个自定义的表单控件,在这个控件中,我们需要实现ControlValueAccessor接口。
import { Component, forwardRef, Input } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
const RATING_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => RatingComponent),
multi: true
};
@Component({
selector: 'app-rating',
templateUrl: './rating.component.html',
styleUrls: ['./rating.component.css'],
providers: [RATING_VALUE_ACCESSOR]
})
export class RatingComponent implements ControlValueAccessor {
//控件禁用状态
@Input() disabled: boolean = false;
//控件值
private _ratingValue: number = 0;
private onTouchedCallback: () => void = () => {};
private onChangeCallback: (_: any) => void = () => {};
get ratingValue(): number {
return this._ratingValue;
}
set ratingValue(val: number) {
if (val !== this._ratingValue) {
this._ratingValue = val;
//控件值变化时,调用回调函数,将新值写入到模型中
this.onChangeCallback(val);
}
}
//将模型值写入到控件中
writeValue(val: number) {
if (val !== this._ratingValue) {
this._ratingValue = val;
}
}
//在控件值发生变化时,调用模型中注册的回调函数
registerOnChange(fn: any) {
this.onChangeCallback = fn;
}
//在控件失去焦点时,调用模型中注册的回调函数
registerOnTouched(fn: any) {
this.onTouchedCallback = fn;
}
//设置控件的禁用状态
setDisabledState(isDisabled: boolean) {
this.disabled = isDisabled;
}
rate(rating: number) {
if (!this.disabled) {
this.ratingValue = rating;
//控件值发生变化时,调用回调函数,将新值写入到模型中
this.onChangeCallback(this.ratingValue);
}
}
}
在自定义的表单控件中,我们实现了ControlValueAccessor接口的所有方法。其中,writeValue方法用于将模型值写入到控件中,registerOnChange方法用于在控件值发生变化时,调用模型中注册的回调函数,registerOnTouched方法用于在控件失去焦点时,调用模型中注册的回调函数,setDisabledState方法用于设置控件的禁用状态。
接下来,我们需要在组件中注册这个自定义的表单控件。
import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
ratingControl = new FormControl(3);
}
最后,在模板中使用自定义的表单控件。
<div class="rating">
<app-rating [formControl]="ratingControl" [disabled]="false"></app-rating>
</div>
这样,我们就成功地实现了一个自定义的星级评分控件,并且能够实现双向数据绑定,并且可以禁用控件。
4. 总结
本文主要介绍了Angular中的ControlValueAccessor接口,以及如何利用ControlValueAccessor接口实现可自定义双向数据绑定的表单控件。通过本文的介绍,读者可以了解到ControlValueAccessor接口的作用、核心方法以及实现方式,并且掌握了如何利用ControlValueAccessor接口实现一个自定义的表单控件。