Angular 自定义表单控件 -- CheckboxGroupComponent
ControlValueAccessor
一般我们要实现一个自定义表单控件,首先要做的就是实现 ControlValueAccessor
接口。
ControlValueAccessor 是一个连接表单模型和视图(DOM元素)的接口,自定义的表单控件必须实现这个接口,它的作用是:
- 把 form 模型中值映射到视图中
- 当视图发生变化时,通知 form directives 或 form controls
这个接口提供了以下方法:
interface ControlValueAccessor {
writeValue(obj: any): void //数据由模型更新到视图(model->view)时,方法被调用
registerOnChange(fn: any): void //数据由视图更新到模型(view->model)时,方法被调用
registerOnTouched(fn: any): void
setDisabledState(isDisabled: boolean)?: void
}
NG_VALUE_ACCESSOR
利用这一 Token
可将控件注册成为可让表单访问到其值的控件,使用方法如下:
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CheckboxGroupComponent),
multi: true
}]
Note:Token NG_VALIDATORS 可将控件注册成为可让表单访问到其验证状态的控件。
自定义表单控件 CheckboxGroupComponent
1. 控件模板(基于Ionic)
<ion-grid>
<ion-row>
<label>{{ groupName }}</label>
<ion-col *ngFor="let e of options">
<section>
<mat-checkbox [disabled]="disabled"
[checked]="this.model.length && this.model.indexOf(e.id) > -1"
[value]="e[value]"
(change)="setValue(e)">
{{ e[display] }}
</mat-checkbox>
</section>
</ion-col>
</ion-row>
</ion-grid>
2.组件类
export class CheckboxGroupComponent implements ControlValueAccessor {
@Input() options: any = [] //checkbox数据数组 包含 id/value/display 三个属性
@Input() disabled: boolean = false //控件可用性
@Input() display: string //display是展示到界面的名称
@Input() value: string //value是提交到后台的数据
@Input() groupName: string //checkboxgroup的标题
model: any = [] //存放每个checked value 实时变化
onChange = (_: any) => {}
onTouched = () => {}
constructor() {
}
setValue(obj){ //复选框的状态改变时触发
let { id } = obj //解构赋值 这里也可以写value
let index = this.model.indexOf(id)
if(index > -1){
//model中若存在则移除
this.model.splice(index, 1)
//onChange方法将值的改变传递给外部 如果不调用这一方法表单控件中得不到任何数据
//这个this.model也就是控件使用时与 ngModel 绑定的值
this.onChange(this.model)
}else{
//不存在则添加
this.model.push(id)
this.onChange(this.model)
}
console.log(this.model)
}
writeValue(value: any){
if(value && value.length){
this.model = value
}else {
this.model = []
}
}
registerOnChange(fn: any){
this.onChange = fn
}
registerOnTouched(fn: any){
this.onTouched = fn
}
}
3. 注册为表单控件
@Component({
selector: 'checkbox-group',
templateUrl: 'checkbox-group.html',
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CheckboxGroupComponent),
multi: true
}]
})
4. 控件使用
<checkbox-group [groupName]="'爱好:'" [options]="hobbies" [display]="'title'"
[value]="'value'" [(ngModel)]="hobby" formControlName="hobby">
</checkbox-group>
<p>{{inform.get('hobby').value | json}}</p>
hobbies = [
{ id: 1, title: '电影', value: 'movie' },
{ id: 2, title: '音乐', value: 'song' },
{ id: 3, title: '登山', value: 'mountain' },
{ id: 4, title: '阅读', value: 'read' },
{ id: 5, title: '游泳', value: 'swim' },
]
使用响应式表单,控件名为hobby
,显示效果如下: