视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Angular使用ControlValueAccessor创建自定义表单控件
2020-11-27 22:00:22 责编:小采
文档


在 Angular 自定义表单控件,有时你想要的输入不是标准的文本输入、选择或复选框。通过实现ControlValueAccessor 接口并将组件注册为 NG_VALUE_ACCESSOR,您可以将自定义表单控件无缝地集成到模板驱动或响应表单中,就像它是本地表单一样!

ControlValueAccessor

ControlValueAccessor 是一个接口,充当Angular API 和 DOM 元素之间的桥梁

ControlValueAccessor 是一个连接表单模型和视图(DOM元素)的接口,自定义的表单控件必须实现这个接口,它的作用是:

  • 把 form 模型中值映射到视图中
  • 当视图发生变化时,通知 form directives 或 form controls
  • Angular 引入这个接口的原因是,不同的输入控件数据更新方式是不一样的。例如,对于我们常用的文本输入框来说,我们是设置它的 value 值,而对于复选框 (checkbox) 我们是设置它的 checked 属性。实际上,不同类型的输入控件都有一个 ControlValueAccessor,用来更新视图

    Angular 中常见的 ControlValueAccessor 有:

  • DefaultValueAccessor - 用于 text 和 textarea 类型的输入控件
  • SelectControlValueAccessor - 用于 select 选择控件
  • CheckboxControlValueAccessor - 用于 checkbox 复选控件
  • export interface ControlValueAccessor {
     writeValue(obj: any) : void
     registerOnChange(fn: any) : void
     registerOnTouched(fn: any) : void
    }

    writeValue(obj:any)是将表单模型中的值写入视图中。

    writeValue(value: any): void {
     this._renderer.setProperty(this._elementRef.nativeElement, 'value', value);
    }
    

    registerOnChange(fn:any)是一个方法,用于注册在视图中的某些内容发生更改时应调用的处理程序。它获取一个函数,告诉其他表单指令和表单控件更新其值。

    registerOnChange(fn: (_: any) => void): void {
     this._onChange = fn;
    }
    

    registerOnTouched(fn:any)与registerOnChange()此类似,它专门为控件接收触摸事件时注册一个处理程序。

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

    setDisabledState?(isDisabled: boolean): void; 是一个可选的方法,设置自定义表单的状态

    setDisabledState(isDisabled: boolean): void {
     this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
    }
    

    AbstractValueAccessor

    我们可以把 ControlValueAccessor 中的方法写在一个抽象类中,不同的组件可以实现这个基类

    export abstract class AbstractValueAccessor implements ControlValueAccessor {
     
     private _value: any = '';
     
     get value(): any {
     return this._value;
     }
    
     set value(v: any) {
     if (v !== this._value) {
     this._value = v;
     this.onChange(v);
     this.onTouched();
     }
     }
    
     writeValue(value: any) {
     this._value = value;
     }
    
     onChange = (_) => {};
     onTouched = () => {};
    
     registerOnChange(fn: (_: any) => void): void {
     this.onChange = fn;
     }
    
     registerOnTouched(fn: () => void): void {
     this.onTouched = fn;
     }
    }
    
    export function MakeProvider(type: any): { provide: any, useExisting: any, multi: boolean} {
     return { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => type), multi: true };
    }

    Example

    自定义一个 list 控件,可以选择年级

    在线预览
    git仓库

    下载本文
    显示全文
    专题