angular2 通过 ControlValueAccessor NG_VALUE_ACCESSOR实现自定义表单控件

一、演示自定义控件的双向绑定

二、如何实现

cform.component.ts(自定义表单控件CformComponent 的实现,注意下里面的注释段落)

import { Component, OnInit, Input, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

@Component({
  selector: 'app-cform',
  template: `{{info}}
<button (click)="changeInfo()">改变info的值</button>`,
  styleUrls: ['./form-c.component.css'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => CformComponent),
      multi: true
    }
  ]
})
export class CformComponent implements OnInit, ControlValueAccessor {

  info = '';

  onModelChange = (val) => {};
  onTouched = (val) => {};

  constructor() { }
  
  // 该方法用于将模型中的新值写入视图或 DOM 属性中,即model->view,从组件外输入到组件内会触发该方法
  writeValue(obj: any): void {
    this.info = obj;
  }
  // 设置当控件接收到 change 事件后,调用的函数,可以用来通知外部,组件内部值已经发生变化,即view->model,要主动调用this.onModelChange方法才可以。
  registerOnChange(fn: any): void {
    this.onModelChange = fn;
  }

  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }

  setDisabledState?(isDisabled: boolean): void {
    throw new Error('Method not implemented.');
  }

  ngOnInit() {
  }
  
  // 改变值然后通知组件外面,值已经变化了
  changeInfo() {
    this.info = 'another value';
    this.onModelChange(this.info);
    this.onTouched(this.info);
  }

}

app.component.html(自定义表单控件的使用)

<div [formGroup]="formGroup">
  <app-cform formControlName="name" #appCform></app-cform>
</div>

app.component.ts(自定义表单控件的使用)

import { Component, ViewChild } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { CformComponent } from './cform/form-c.component';
import { timer, interval } from 'rxjs';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  ……

  @ViewChild('appCform') appCform: CformComponent;
  formGroup = new FormGroup({
    name: new FormControl('just a test')
  });

  constructor(private cdRef: ChangeDetectorRef) {
    // 立即发出值, 然后每5秒发出值
    const source = timer(0, 5000).subscribe(value => {
      console.log(value);
      console.log(this.formGroup.value);
    });
  }
  ……
}

三、简单讲解

基本流程:实现angular自定义表单控件,得组件实现ControlValueAccessor这个接口,并且实现该接口的4个方法(4个方法看上面实现代码的逻辑。)。然后就完活。

writeValue 当这个组件初始化的时候,外面传入这个组件内部的值

registerOnChange

registerOnTouched

setDisabledState

NG_VALUE_ACCESSOR      类型 const,也就是提供者令牌

官网的解释:用于为表单控件提供ControlValueAccessor。

ControlValueAccessor    类型 interface

官网的解释:定义一个接口,该接口充当 Angular 表单 API 和 DOM 中的原生元素之间的桥梁,实现此接口以创建与 Angular 表单集成的自定义表单控件指令。

从该段话的描述不难发现,要想实现angular的自定义表单构件必须要实现这个ControlValueAccessor接口,实现接口那么就要实现接口中的writeValue、registerOnChange、registerOnTouched等方法,而NG_VALUE_ACCESSOR这个提供者用于为表单控件提供ControlValueAccessor服务,所以要在组件中指定提供者,指定所依赖的提供者用到useExisting: forwardRef(() => CformComponent)。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值