Angular学习之ControlValueAccessor接口详解

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接口实现一个自定义的表单控件。