不推荐使用 FormBuilder 组

ufk*_*ufk 26 typescript angular2-formbuilder angular-validation angular

我将我的项目迁移到 angular 11,我注意到我添加的全局验证FormBuilder.group不推荐使用以下消息:

group is deprecated: This api is not typesafe and can result in issues with Closure Compiler renaming.
Use the `FormBuilder#group` overload with `AbstractControlOptions` instead.
Run Code Online (Sandbox Code Playgroud)

所以这已被弃用:

  ingredientForm = this.fb.group({
    ingredientType: ['', Validators.required],
    ingredientFlavor: [''],
    isMultiFlavor: [''],
    ingredientBrand: [''],
    ingredientName: [''],
    imageFile: ['']
  }, {validators: [ValidateThirdNumber.validate]});
Run Code Online (Sandbox Code Playgroud)

如果没有这个validators选项,它就不是。

我的ValidateThirdNumber验证器:

class ValidateThirdNumber {
  static validate(control: AbstractControl): void {
      if (control) {
      const isMultiFlavor = control.get('isMultiFlavor')?.value;
      const ingredientFlavor = control.get('ingredientFlavor')?.value;
      const ingredientBrand = control.get('ingredientBrand')?.value;
      const ingredientName = control.get('ingredientName')?.value;
      if (isMultiFlavor && ingredientFlavor.trim().length === 0) {
        control.get('ingredientFlavor')?.setErrors({required_if: true});
      } else {
        control.get('ingredientFlavor')?.setErrors(null);
      }
      if (!ingredientFlavor && !ingredientBrand && !ingredientName) {
        control.get('ingredientName')?.setErrors({required_at_least: true});
        control.get('ingredientFlavor')?.setErrors({required_at_least: true});
        control.get('ingredientBrand')?.setErrors({required_at_least: true});
      } else {
        control.get('ingredientName')?.setErrors(null);
        control.get('ingredientFlavor')?.setErrors(null);
        control.get('ingredientBrand')?.setErrors(null);
      }
      if (ingredientBrand && ingredientName && ingredientName === ingredientBrand) {
        control.get('ingredientName')?.setErrors({not_the_same: true});
        control.get('ingredientBrand')?.setErrors({not_the_same: true});
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我如何用 AbstractControlOptions 重载它?

Owe*_*vin 25

Problem description

From the documentation we see two different lines with the group() function

group(controlsConfig: { [key: string]: any; }, options?: AbstractControlOptions): FormGroup

AND

group(controlsConfig: { [key: string]: any; }, options: { [key: string]: any; }): FormGroup

The 2nd definition is what is deprecated

The difference in this lines is options?: AbstractControlOptions and options: { [key: string]: any; }

To understand why angular is throwing this error we will now consider AbstractControlOptions

interface AbstractControlOptions {
  validators?: ValidatorFn | ValidatorFn[] | null
  asyncValidators?: AsyncValidatorFn | AsyncValidatorFn[] | null
  updateOn?: 'change' | 'blur' | 'submit'
}
Run Code Online (Sandbox Code Playgroud)

We continue to breakdown the problem by noting that the difference between this structure and your structure is ValidatorFn[]

interface ValidatorFn {
  (control: AbstractControl): ValidationErrors | null
}
Run Code Online (Sandbox Code Playgroud)

Overally, the error is thrown in your case because your Validator function is expected to take a control and return ValidationErrors | null. In the line validate(control: AbstractControl): void, your code actually returns void but expected to return a ValidationError | null

Solution

From the problem description, the solution is to simply modify the ValidatorFn

Ensure that your ValidatorFn returns a ValidationError or if no error returns null From ValidationErrors defination

type ValidationErrors = {
    [key: string]: any;
};
Run Code Online (Sandbox Code Playgroud)

You will need to return a key value pair object e.g {required_if: true}

We can change your code by adding return statements as expected

class ValidateThirdNumber {
  static validate(control: AbstractControl): ValidationErrors | null {
      if (control) {
      const isMultiFlavor = control.get('isMultiFlavor')?.value;
      const ingredientFlavor = control.get('ingredientFlavor')?.value;
      const ingredientBrand = control.get('ingredientBrand')?.value;
      const ingredientName = control.get('ingredientName')?.value;
      if (isMultiFlavor && ingredientFlavor.trim().length === 0) {
        control.get('ingredientFlavor')?.setErrors({required_if: true});
        return ({required_if: true});
      } else {
        control.get('ingredientFlavor')?.setErrors(null);
      }
      if (!ingredientFlavor && !ingredientBrand && !ingredientName) {
        control.get('ingredientName')?.setErrors({required_at_least: true});
        control.get('ingredientFlavor')?.setErrors({required_at_least: true});
        control.get('ingredientBrand')?.setErrors({required_at_least: true});
        return ({required_at_least: true});
      } else {
        control.get('ingredientName')?.setErrors(null);
        control.get('ingredientFlavor')?.setErrors(null);
        control.get('ingredientBrand')?.setErrors(null);
      }
      if (ingredientBrand && ingredientName && ingredientName === ingredientBrand) {
        control.get('ingredientName')?.setErrors({not_the_same: true});
        control.get('ingredientBrand')?.setErrors({not_the_same: true});
        return ({not_the_same: true});
      }
    }
    return null;
  }
}
Run Code Online (Sandbox Code Playgroud)


Rez*_*aba 25

只需更改最后一行:

}, {validators: [ValidateThirdNumber.validate]});
Run Code Online (Sandbox Code Playgroud)

}, {validators: [ValidateThirdNumber.validate]} as AbstractControlOptions);
Run Code Online (Sandbox Code Playgroud)

注意:确保 AbstractControlOptions 位于花括号之外!

就是这样。