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,显示效果如下:

posted @ 2018-08-21 10:33  tt273z  阅读(1867)  评论(0编辑  收藏  举报