美文网首页
Angular 自定义表单控件

Angular 自定义表单控件

作者: 云音流 | 来源:发表于2020-01-11 16:13 被阅读0次

    文章转自我的语雀:https://www.yuque.com/liuyin-zzwa0/angular/custom-form-control

    Angular有两种类型的表单:响应式表单(reactive forms)、模板驱动表单(Template-driven forms)。
    共同基础

    • FormControl 实例用于追踪单个表单控件的值和验证状态。
    • FormGroup 用于追踪一个表单控件组的值和状态。
    • FormArray 用于追踪表单控件数组的值和状态。
    • ControlValueAccessor 用于在 Angular 的 FormControl 实例和原生 DOM 元素之间创建一个桥梁。

    实现自定义表单控件的核心在于:ControlValueAccessor,组件需要实现这个接口的功能。

    interface ControlValueAccessor {
      writeValue(obj: any): void
      registerOnChange(fn: any): void
      registerOnTouched(fn: any): void
      setDisabledState(isDisabled: boolean)?: void
    }
    
    • writeValue(obj: any):该方法用于将模型中的新值写入视图或 DOM 属性中。
    • registerOnChange(fn: any):设置当控件接收到 change 事件后,调用的函数
    • registerOnTouched(fn: any):设置当控件接收到 touched 事件后,调用的函数
    • setDisabledState?(isDisabled: boolean):当控件状态变成 DISABLED 或从 DISABLED 状态变化成 ENABLE 状态时,会调用该函数。该函数会根据参数值,启用或禁用指定的 DOM 元素。

    在组件实现ControlValueAccessor接口后,要能正常使用的话,还需要执行注册操作。

    实现ngModel双向绑定

    导入FormsModule

    import { NgModule } from '@angular/core';
    import { CommonModule } from '@angular/common';
    import { FormsModule } from '@angular/forms';
    import { NgZorroAntdModule } from 'ng-zorro-antd';
    import { City3Component } from './city3.component';
    
    @NgModule({
      imports: [CommonModule, FormsModule, NgZorroAntdModule],
      declarations: [City3Component],
      exports: [City3Component],
    })
    export class City3Module {}
    

    组件需要注入一个Provider去实现。

    /**
     * template-driven forms 模板驱动表单
     * 实现 ngModel
     */
    const EXE_CITY3_VALUE_ACCESSOR: ExistingProvider = {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => City3Component),
      multi: true,
    };
    
    @Component({
      selector: 'app-city3',
      templateUrl: './city3.component.html',
      styleUrls: ['./city3.component.less'],
      encapsulation: ViewEncapsulation.None,
      changeDetection: ChangeDetectionStrategy.OnPush,
      providers: [EXE_CITY3_VALUE_ACCESSOR]
    })
    export class City3Component implements OnInit, ControlValueAccessor {
      // ...
    }
    

    实现formControl

    导入ReactiveFormsModule

    import { NgModule } from '@angular/core';
    import { CommonModule } from '@angular/common';
    import { ReactiveFormsModule } from '@angular/forms';
    import { NgZorroAntdModule } from 'ng-zorro-antd';
    import { City3Component } from './city3.component';
    
    @NgModule({
      imports: [CommonModule, ReactiveFormsModule, NgZorroAntdModule],
      declarations: [City3Component],
      exports: [City3Component],
    })
    export class City3Module {}
    

    实现自定义校验器

    • 使用 ValueProvider 注册
    /**
     * 直接提供给provider使用的校验器
     * @param control AbstractControl
     */
    const validateSelectValue: ValidatorFn = (control: AbstractControl): ValidationErrors => {
      if (control.touched) {
        const reg = CITY_REGEXPS[2];
        if (control.value) {
          return reg.test(control.value) ? null : { invalid: true };
        } else {
          return null;
        }
      }
    };
    /**
     * provider 默认校验使用的方式
     */
    const EXE_CITY3_VALIDATOR: ValueProvider = {
      provide: NG_VALIDATORS,
      useValue: validateSelectValue,
      multi: true,
    };
    
    @Component({
      selector: 'app-city3',
      templateUrl: './city3.component.html',
      styleUrls: ['./city3.component.less'],
      encapsulation: ViewEncapsulation.None,
      changeDetection: ChangeDetectionStrategy.OnPush,
      providers: [EXE_CITY3_VALIDATOR]
    })
    export class City3Component implements OnInit, ControlValueAccessor {
      // ...
    }
    
    • 使用 ExistingProvider 注册
    /**
     * 自定义校验所使用的校验方式,组件要额外实现 Validator
     */
    const EXE_CITY3_VALIDATOR_2: ExistingProvider = {
      provide: NG_VALIDATORS,
      useExisting: forwardRef(() => City3Component),
      multi: true,
    };
    @Component({
      selector: 'app-city3',
      templateUrl: './city3.component.html',
      styleUrls: ['./city3.component.less'],
      encapsulation: ViewEncapsulation.None,
      changeDetection: ChangeDetectionStrategy.OnPush,
      providers: [EXE_CITY3_VALIDATOR_2]
    })
    export class City3Component implements OnInit, ControlValueAccessor, Validator {
      // ...
      /**
       * 实现自定义校验,写在组件类可介入入参
       * @param control AbstractControl
       */
      validate(control: AbstractControl): ValidationErrors | null {
        if (control.touched) {
          const reg = CITY_REGEXPS[2];
          if (control.value) {
            return reg.test(control.value) ? null : { invalid: true };
          } else {
            return null;
          }
        }
      }
    }
    

    参考:https://segmentfault.com/a/1190000009070500https://github.com/NG-ZORRO/ng-zorro-antd/tree/master/components/select
    自定义表单控件完整代码:https://github.com/superchow/ng-login-demo/tree/master/src/app/components/city3

    相关文章

      网友评论

          本文标题:Angular 自定义表单控件

          本文链接:https://www.haomeiwen.com/subject/ckqbactx.html