• angular11源码探索十六[自定义表单组件封装]


    AbstractControl

    api

    源码validator

    由注册到此的所有同步验证器组成的同步验证器函数

     get validator(): ValidatorFn|null {
        return this._composedValidatorFn || null;
      }
    
    export function composeValidators(validators: Array<Validator|ValidatorFn>): ValidatorFn|null {
      return validators != null ? Validators.compose(normalizeValidators<ValidatorFn>(validators)) :null;
    }
    将多个验证器组合成一个返回联合的函数
    *所提供控件的个别错误映射
     static compose(validators: null): null;
      static compose(validators: (ValidatorFn|null|undefined)[]): ValidatorFn|null;
      static compose(validators: (ValidatorFn|null|undefined)[]|null): ValidatorFn|null {
        if (!validators) return null;
        const presentValidators: ValidatorFn[] = validators.filter(isPresent) as any;
        if (presentValidators.length == 0) return null;
    
        return function(control: AbstractControl) {
          return mergeErrors(executeValidators<ValidatorFn>(control, presentValidators));
        };
      }
    function mergeErrors(arrayOfErrors: (ValidationErrors|null)[]): ValidationErrors|null {
      let res: {[key: string]: any} = {};
        // 没有使用数组的形式,chrome 80 之前有个bug,
        // 我们发现它把所有报错信息放在这个对象中
      arrayOfErrors.forEach((errors: ValidationErrors|null) => {
        res = errors != null ? {...res!, ...errors} : res!;
      });
    
      return Object.keys(res).length === 0 ? null : res;
    }
    
    

    案例

     addFn(c: FormControl): ValidationErrors | null {
        return c.value == 11 ? {sex: true} : null;
      }
     this.profileForm = new FormGroup({
      firstName: new FormControl('xxx', [Validators.required, Validators.max(8), Validators.min(1), this.addFn])
              })
      //验证1,3没有通过
        console.log(this.profileForm.get('firstName').validator(new FormControl(11)));
        // {max: {max: 8, actual: 11},sex: true}
    

    asyncValidator

    异步校验

    export interface AsyncValidator extends Validator {
      validate(control: AbstractControl):
          Promise<ValidationErrors|null>|Observable<ValidationErrors|null>;
    }
    Promise.resolve(null)
    of(null)
    of({name1:true})
    
    

    AbstractControls

    逻辑共享跨越FormControlFormGroupFormArray

    // FG - FormGroup
    // FA - FormArray
    // FC - FormControl
    
        FG
      /   
    FC    FG
        /    
      FC     FA
            / | 
          FC FC FC
    

    CheckboxControlValueAccessor

    复选框

    • input[type=checkbox][formControlName]
    • input[type=checkbox][formControl]
    • input[type=checkbox][ngModel]

    事件

    change事件,blur事件

    formControl

    <form [formGroup]="profileForm">
      <label >
        <input type="checkbox" formControlName="lastName" >
      </label>
      <label >
        <input type="checkbox" formControlName="firstName" >
      </label>
    </form>
    
     profileForm: FormGroup;
      ngOnInit(): void {
        this.profileForm = new FormGroup({
          firstName: new FormControl(false),
          lastName: new FormControl(false)
        });
        this.profileForm.valueChanges.subscribe(console.log)
      }
    

    formControlName

    <form [formGroup]="profileForm">
      <div formArrayName="firstArr" *ngFor="let item of getArr;let i=index">
        <label>
          <input type="checkbox" [formControlName]="i">
        </label>
      </div>
    </form>
    
    export class TwoComponent implements OnInit, AfterViewInit {
      profileForm: FormGroup;
      constructor() {
        this.profileForm = new FormGroup({
          firstArr: new FormArray(
            [
              new FormControl(false),
              new FormControl(false),
              new FormControl(false),
            ]
          )
        });
      }
      get getArr(): FormArray {
        return this.profileForm.get('firstArr')?.controls
      }
     ngOnInit(): void {
        this.profileForm.get('firstArr').valueChanges.subscribe(console.log)
      }
    }
    

    ngModel

    可以使用事件拿稍微好一些

    <input type="checkbox" [(ngModel)]="objArr.age1" (change)="clickChange($event)">
    <input type="checkbox" [(ngModel)]="objArr.age2" (blur)="blurChange()">
    <input type="checkbox" [(ngModel)]="objArr.age3">
      
     objArr={
        age1:false,
        age2:false,
        age3:false
      }
     
      blurChange(){
        console.log(this.objArr);
      }
      clickChange(e) {
        console.log(e,this.objArr);
      }
    

    ControlValueAccessor自定义表单组件

    interface ControlValueAccessor {
      writeValue(obj: any): void
      registerOnChange(fn: any): void
      registerOnTouched(fn: any): void
      setDisabledState(isDisabled: boolean)?: void
    }
    

    该接口充当Angular表单API和DOM中的本机元素之间的桥梁。

    使用方法可以参考CheckboxControlValueAccessor源码

    经常很多的尝试和研究终于弄懂了

    <app-b [formControl]="formControl" (change)="clickChange($event)"></app-b>
    
     formControl = new FormControl({ value: { scope: '12', query: '44' }})
    
    ngAfterViewInit() {
       	 //类似change的事件
      	  this.formControl.valueChanges.subscribe(console.log)
    }
      //失去焦点
      clickChange(e){
        console.log(1,this.formControl.value);
      }
    

    子组件,注意了,要查看具体步奏

    <div [formGroup]="form">
      <label >
        <input type="text" formControlName="scope">
        <input type="text" formControlName="query">
      </label>
    </div>
    
    
    @Component({
      selector: 'app-b',
      templateUrl: './b.component.html',
      styleUrls: ['./b.component.scss'],
      providers: [
        {
          provide: NG_VALUE_ACCESSOR,
          useExisting: forwardRef(() => BComponent),
          multi: true,
        }
      ]
    })
    export class BComponent implements OnInit, ControlValueAccessor, AfterViewInit {
      form: FormGroup;
         constructor(
        private fb: FormBuilder,
      	) {
        this.form = this.fb.group({
          scope: new FormControl(''),
          query: new FormControl(''),
        });
      }
        // 父传子赋值
         @Input()
          set value(value: FormFieldValue) {
            this.form.patchValue(value);
          }
        ngAfterViewInit() {
            this.form.valueChanges.subscribe(value => {
                this.onChange(value)
              }
            )
          } 
          //父传子的时候赋值给子
      writeValue(obj: any): void {
        this.value = obj;
      }
      //同步更新的事件
      registerOnChange(fn: any): void {
        this.onChange = fn;
      }
      //失去焦点的事件
      registerOnTouched(fn: any): void {
        this.onToutch = fn;
      }
      //父传子禁用的值
      setDisabledState(isDisabled: boolean): void {
        this.disabled = isDisabled;
      }
    }
    

    给属性默认添加事件

    官网

    源码

    [ngModel],[formControl],[formControlName]
     host: {
        '(input)': '$any(this)._handleInput($event.target.value)',
        '(blur)': 'onTouched()',
        '(compositionstart)': '$any(this)._compositionStart()',
        '(compositionend)': '$any(this)._compositionEnd($event.target.value)'
      },
          都具有获取change事件和blur事件 
    

    例如

    <form [formGroup]="profileFormOne">
      <input type="text" formControlName="lastName1" (input)="clickChange($event.target)" (blur)="blurChange($event.target)">
      <input type="text" formControlName="firstName">
    </form>    
    //change事件
     clickChange(e: EventTarget) {
        console.log(e.value);
      }
    // blur事件
      blurChange(target: EventTarget) {
        console.log(target.value);
      }
    
    '(compositionstart)' '(compositionend)' 这两种实验无效
    
  • 相关阅读:
    WRF rsl.out文件研究
    ERA-Interim 的变量TCW和VIWV可降水量
    sudo apt update 没有 Release 文件
    线性斜压模式LBM学习&安装实录
    PGI 用户手册之 Site-Specific Customization of the Compilers
    ERA5气压层数据驱动WRF的一些问题
    OpenMP fortran 学习
    crontab计划运行shell脚本,调用ncl执行失败
    CDO学习2 CDO 入门教程Tutorial
    guide, manual, tutorial之间的区别
  • 原文地址:https://www.cnblogs.com/fangdongdemao/p/14238813.html
Copyright © 2020-2023  润新知