在Angular验证器中链接两个字段

我有一个Angular 9表单,其中四个字段相关。一个是复选框,其余为输入。选中此复选框时,输入不应为空,但未选中时,则无关紧要。我想为此进行验证,以便仅当一个字段为空并且第一个字段设置为true时才会出现错误。

我还考虑过创建一个表示选中标记状态的本地布尔值,然后将其传递给验证器。

export function linkedFieldValidator(toggler: boolean): ValidatorFn {
  console.log('updated');
  return (control: AbstractControl): {[key: string]: any} | null => {
    return (toggler && control.value === '') ? {linkedField: {value: control.value}} : null;
  };
}

...
field: new FormControl('', linkedFieldValidator(this.checkboxvalue)),
...

但是,这是行不通的,我想这是因为它仅传递一次布尔值,之后不更新。即使打电话updateValueAndValidity()也不起作用,这对我来说很奇怪(如果不是,那么它的目的是什么?)。

我的结构FormGroup看起来像这样:

this.form = this.formBuilder.group({
  name: new FormControl(''), // don't care
  address: new FormControl(''), // don't care
  car: new FormControl(false), // do care - this is the checkmark
  license_plate: new FormControl('', Validators.pattern(MY_LICENSE_PLATE_REGEX)), // shouldn't be empty when car
  mileage: new FormControl('') // shouldn't be empty when car
  hair: new FormControl(false), // do care - this is the checkmark
  hair_color: new FormControl(''), // shouldn't be empty when hair
});

如您所见,我彼此之间有几个,FormControll并且我只希望将其中的几个链接在一起。要注意的另一重要事项是,如果违反了其中一个条件,虽然可以使整个表单无效,但我希望能够分别解决每个错误,以便可以在适当的位置显示适当的消息。

我没有其他想法了,有人可以帮我吗?我正在使用反应形式。

开发人员033

问题是您只将初始值传递给该linkFieldValidator函数。

为了有值动态,你可以通过linkFieldValidator通过FormGroup,就像这样:

readonly formGroup = this.formBuilder.group(
  {
    checkbox: '',
    name: ''
  },
  { validator: linkedFieldValidator }
);

完整样本:

import { ChangeDetectionStrategy, Component } from '@angular/core';
import {
  AbstractControl,
  FormBuilder,
  FormGroup,
  ValidationErrors,
  ValidatorFn,
} from '@angular/forms';

export const linkedFieldValidator = (formGroup: FormGroup): ValidationErrors | null => {
  const [checkboxFormControlValue, nameFormControlValue] = [
    formGroup.get('checkbox')!.value,
    formGroup.get('name')!.value
  ];

  return checkboxFormControlValue && !nameFormControlValue
    ? { linkedField: { value: nameFormControlValue } }
    : null;
};

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: 'input-overview-example',
  styleUrls: ['input-overview-example.css'],
  templateUrl: 'input-overview-example.html'
})
export class InputOverviewExample {
  readonly formGroup = this.formBuilder.group(
    {
      checkbox: '',
      name: ''
    },
    { validator: linkedFieldValidator }
  );

  constructor(private readonly formBuilder: FormBuilder) {}
}

演示


编辑1:如果您需要将错误保存在每个表单控件中,则可以将其更改linkedFieldValidator为:

export const linkedFieldValidator = (formGroup: FormGroup): null => {
  const { value: checkboxFormControlValue } = formGroup.get('checkbox')!;
  const inputFormControls = [
    formGroup.get('input1')!,
    formGroup.get('input2')!,
    formGroup.get('input3')!,
  ];

  inputFormControls.forEach(inputFormControl => {
    const { value } = inputFormControl;
    const errors = checkboxFormControlValue && !value ? { linkedField: { value } } : null;
    inputFormControl.setErrors(errors);
  });

  return null;
};

请注意,如果需要保留其他错误,则可能需要先进行一些处理setErrors

演示

编辑2

对于可以具有多个链接字段的通用方法,可以执行以下操作:

type LinkedFormControl = Record<string, string | readonly string[]>;

const arrayify = <T>(itemOrItems: T | readonly T[]): readonly T[] => {
  return Array.isArray(itemOrItems) ? itemOrItems : [itemOrItems];
};

const getErrorObjectSanitized = <T extends object>(obj: T): T | null => {
  return Object.keys(obj).length === 0 ? null : obj;
};

const getErrorsFor = (
  checkerValue: boolean,
  formControl: FormControl,
): object | null => {
  const { errors, value } = formControl;
  const { error, ...oldErrors } = errors || {};
  const processedErrors = {
    ...(checkerValue && !value ? { error: true } : {}),
    ...oldErrors,
  };

  return getErrorObjectSanitized(processedErrors);
};

export const linkedFieldValidator = (linkedFormControls: LinkedFormControl) => {
  return (formGroup: FormGroup): ValidationErrors | null => {
    Object.keys(linkedFormControls).forEach(key => {
      const { value: checkerValue } = formGroup.get(key)!;
      const dependentKeys = arrayify(linkedFormControls[key]);

      dependentKeys
        .map(dependentKey => formGroup.get(dependentKey)!)
        .forEach((dependentFormControl: FormControl) => {
          dependentFormControl.setErrors(
            getErrorsFor(checkerValue, dependentFormControl),
          );
        });
    });

    return null;
  };
};

...,呼叫将如下所示:

{
  validator: linkedFieldValidator({
    car: ['license_plate', 'mileage'],
    hair: 'hair_color',
  }),
},

演示

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章