Angular 上的间接条件必需验证(嵌套 属性)

Indirectly Conditional Required Validations (nested property) on Angular

我正在检查此 question 及其答案,以便 post。

public isFirst = false;
public isSecond = false;

private buildFormGroup() {
    const internalFormGroup = this.formBuilder.group({
      idTypeCode: ['', [Validators.required, Validators.min(1)]],
      master: [true],
      slave: [''],
      fieldSlave: [''], // Validations depends indirectly on idTypeCode !!! HERE
    });

    return internalFormGroup;
}

private conditionalValidator(masterName: string, masterValue: any, slaveName: string, validators: any) {
    if (this.formGroup) {
      const masterControl = this.formGroup.get(masterName);
      if (masterControl) {
        masterControl.valueChanges.subscribe((value) => {
          const slaveControl = this.formGroup.get(slaveName);
          if (slaveControl) {
            if (value === masterValue) {
              slaveControl.setValidators(validators);
            } else {
              slaveControl.clearValidators();
            }
            slaveControl.updateValueAndValidity();
          }
        });
      }
    }
}


public onTypeCodeChange(event: MatSelectChange) {
    const selectedId = +event;
    const selectedTypeCode = this.typeCodes.find((typeCode) => typeCode.id === selectedId);
    this.isFirst = selectedTypeCode?.codeEnum === CodeEnum.First;
    this.isSecond = selectedTypeCode?.codeEnum === CodeEnum.Second;
}

我跳过填充可观察对象的代码typeCodes$

public readonly typeCodes$: Observable<TypeCodeDto[]>;
private typeCodes: TypeCodeDto[] = [];

public ngOnInit(): void {
    this.typeCodes$.subscribe((typeCodes) => {
      this.typeCodes = typeCodes;
    });
    this.conditionalValidator('master', false, 'slave', [Validators.required, Validators.min(1)]);
}

如您所见,conditionalValidator 方法的使用非常简单!!!

但是,我有一个包含一个枚举的接口

    export interface TypeCodeDto {
      id?: number;
      name?: string;
      codeEnum?: CodeEnum;
    }

    export enum CodeEnum {
      None = 0,
      First = 1,
      Second = 2,
    }

在我的 HTML 中,我将 Select 与之前的可观察 typeCodes$

一起使用
  <mat-select
    formControlName="idTypeCode"
    [required]="formGroup.controls.idTypeCode.invalid"
    (ngModelChange)="onTypeCodeChange($event)"
  >
    <mat-option *ngFor="let typeCode of typeCodes$ | async" [value]="typeCode.id">
      {{ typeCode.name }}
    </mat-option>
  </mat-select>

现在我有一个复杂的情况,在我的HTML中,当Select(或idTypeCode)对应一个TypeCodeDtocodeEnum等于Second 我需要申请:

fieldSlave: ['', [Validators.required, Validators.maxLength(256), Validators.minLength(1)]],

如何实现?

https://stackblitz.com/edit/angular-ivy-9giuxs?file=src%2Fapp%2Fapp.component.html

添加一个可观察对象:

  private subCodeEnum = new Subject<CodeEnum>();

用你的方法!

  public onTypeCodeChange(event: MatSelectChange) {
    const selectedId = +event;
    const selectedTypeCode = this.typeCodes.find(
      (typeCode) => typeCode.id === selectedId
    );
    this.subCodeEnum.next(selectedTypeCode?.codeEnum);
  }

创建(或替换您的 conditionalValidator 方法的代码):

  private conditionalObservableValidator(
    masterObservable: Observable<any> | null | undefined,
    masterValue: any,
    slaveControl: AbstractControl | null,
    trueValidators: ValidatorFn | ValidatorFn[] | null,
    falseValidators?: ValidatorFn | ValidatorFn[] | null
  ) {
    if (slaveControl && masterObservable) {
      masterObservable.subscribe(
        (value) => {
          if (value === masterValue) {
            slaveControl.setValidators(trueValidators || null);
          } else {
            slaveControl.setValidators(falseValidators || null);
          }
          slaveControl.updateValueAndValidity();
        }
        
      );
    }
  }

如何使用?

  public ngOnInit(): void {
    //
    
    this.conditionalObservableValidator(
      this.formGroup.get('master').valueChanges,
      false,
      this.formGroup.get('slave'),
      [Validators.required, Validators.min(1),]
    );

    this.conditionalObservableValidator(
      this.subCodeEnum,
      CodeEnum.Second,
      this.formGroup.get('fieldSlave'),
      [Validators.required, Validators.maxLength(256), Validators.minLength(1)],
      null // Last argument is Not necessary
    );
  }

编辑:

您可以在 HTML 模板上使用:selectionChange

<mat-select
  formControlName="idTypeCode"
  [required]="formGroup.controls.idTypeCode.invalid"
  (selectionChange)="onTypeCodeChange($event.value)"
>
  <mat-option
    *ngFor="let typeCode of typeCodes$ | async"
    [value]="typeCode.id"
  >
    {{ typeCode.name }}
  </mat-option>
</mat-select>

或者您的 HTML 模板

上既没有 (ngModelChange) 也没有 (selectionChange)
<mat-select
  formControlName="idTypeCode"
  [required]="formGroup.controls.idTypeCode.invalid"
>
  <mat-option
    *ngFor="let typeCode of typeCodes$ | async"
    [value]="typeCode.id"
  >
    {{ typeCode.name }}
  </mat-option>
</mat-select>

稍后你的formGroup被创建,然后你订阅idTypeCode模态中的formControl变化:

  public ngOnInit(): void {
    // Some code thart you need

    this.formGroup = this.buildFormGroup();

    this.formGroup.get('idTypeCode')?.valueChanges.subscribe((value) => {
      // Do Here your Requirements
      console.log(`value: ${value}`);
    });

    // Your other code
  }