как сделать настраиваемый валидатор в angular для проверки поля формы на основе другого поля формы?

Машинопись для компонента:

export class EtcAddAuthorityComponent implements OnInit {
   addAuthorityForm: FormGroup;
   authTypes: any[] = [];
   loading = false;
   numericRegex = /^[0-9]*$/;

   alphabeticRegex = /^[a-zA-Z]*$/;

   constructor(
      private readonly dialogRef: MatDialogRef<EtcAddAuthorityComponent>,
      private readonly fb: FormBuilder,
      private readonly toastr: ToastrService,
      private readonly ecmService: EcmService,
      private readonly ecmToolChangeService: EcmToolChangeService,
      private readonly cgpAlertDialogService: CgpAlertDialogService,
      @Inject(MAT_DIALOG_DATA) public readonly selectedTool: any
   ) {
      this.addAuthorityForm = this.fb.group({
         authNumber: ['', [Validators.maxLength(20), Validators.pattern(this.alphabeticRegex)]],
         authNumberN: ['', [Validators.required, Validators.maxLength(20), Validators.pattern(this.numericRegex)]],
         authTypeName: ['', [Validators.required, Validators.maxLength(10)]],
         authDescription: ['', [Validators.maxLength(500)]]
      });
   }



   ngOnInit() {
      this.loading = true;
      this.ecmService.getAuthTypeCriteria()
         .subscribe({
            next: (res) => {
               if (res) {
                  this.authTypes = res;
               }
            },
            complete: () => this.loading = false
         });
   }

   onCancelClick() {
      this.dialogRef.close();
   }

   onAddClick() {

      const authNFieldifAuthTypeName = this.authFieldCheck();
      if (authNFieldifAuthTypeName === true) {
         return;
      }
      else {

         const body = {
            ...this.addAuthorityForm.value,
            partChangeId: this.selectedTool.partChangeId,
            toolChangeId: this.selectedTool.toolChangeId
         };

         this.loading = true;
         this.ecmToolChangeService.addAuthority(body)
            .subscribe({
               next: (res) => {
                  this.cgpAlertDialogService.showAlertDialog({
                     title: 'Add Authority',
                     message: 'Authority was added successfully!',
                     alert: cgpAlertTypes.success,
                     closeLabel: 'OK'
                  }).afterClosed().subscribe(() => this.dialogRef.close({ reload: true }));
               },
               error: (err) => {
                  this.loading = false;
                  this.cgpAlertDialogService.showAlertDialog({
                     title: 'Add Authority',
                     message: 'Authority could not be added. Please try again!',
                     alert: cgpAlertTypes.danger,
                     closeLabel: 'OK'
                  });
               },
               complete: () => this.loading = false
            });
      }
   }

   authFieldCheck(): boolean {
      const matched: boolean = (this.addAuthorityForm.controls.authTypeName.value === 'EWO') && (!this.addAuthorityForm.controls.authNumber.value);

      if (matched) {
         this.addAuthorityForm.controls.authTypeName.setErrors({
            notFilled: true
         });
      }
      else {
         this.addAuthorityForm.controls.authTypeName.setErrors({ notMatched: false });
      }
      return matched;
   }


}

HTML-код:

<h1 mat-dialog-title>Add Authority</h1>
<div mat-dialog-content>
   <form class="flex-dialog-container" [formGroup]="addAuthorityForm">
      <mat-form-field>
         <mat-label>Authority #(alpha)</mat-label>
         <input matInput autocomplete="off" formControlName="authNumber" #authNumber>
         <mat-error *ngIf="authNumber.value?.length > 20">Cannot exceed 20 characters.</mat-error>
      </mat-form-field>

      <mat-form-field>
         <mat-label>Authority #(numeric)</mat-label>
         <input matInput autocomplete="off" formControlName="authNumberN" #authNumberN>
         <mat-error *ngIf="addAuthorityForm.controls.authNumberN.hasError('required')">Required</mat-error>
         <mat-error *ngIf="authNumberN.value?.length > 20">Cannot exceed 20 characters.</mat-error>   
      </mat-form-field>

      <mat-form-field>
         <mat-label>Authority Type</mat-label>

         <mat-select formControlName="authTypeName">
            <mat-option *ngFor="let at of authTypes" [value]="at.authTypeName">
               {{at.authTypeName}}
            </mat-option>
         </mat-select>
         <mat-error *ngIf="addAuthorityForm.controls.authTypeName.hasError('required')">Required</mat-error>
         <mat-error *ngIf=" this.addAuthorityForm.controls.authTypeName.hasError('notFilled')">Authority #(alpha) required</mat-error>
      </mat-form-field>

      <mat-form-field>
         <mat-label>Authority Description</mat-label>
         <input matInput autocomplete="off" formControlName="authDescription" #authDescription>
         <mat-error *ngIf="authDescription.value?.length > 500">Cannot exceed 500 characters.</mat-error>
      </mat-form-field>

   </form>

</div>
<div mat-dialog-actions class="mat-dialog-actions-end no-margin">
   <button mat-raised-button mat-dialog-close cdkFocusInitial (click)="onCancelClick()"
      (keypress.enter)="onCancelClick()">Cancel</button>
   <button mat-raised-button color="primary" (click)="onAddClick()" (keypress.enter)="onAddClick()" [disabled]="addAuthorityForm.invalid">Add</button>
</div>

Это мое диалоговое окно добавления: диалоговое окно добавления

Как добавить настраиваемую проверку, чтобы при выборе опции "EWO" в раскрывающемся списке "Тип полномочий" отображалась ошибка, если не было введено "Полномочия № (Альфа)". Но он не должен показывать никаких ошибок, если в раскрывающемся списке "Тип полномочий" выбрана опция "EWO".

2 ответа

Решение

Вы можете отключить "Авторитет", если не выбрали EWO, поэтому Angular не проверяет, требуется ли это или нет. Для отключения / включения необходимо использовать методы disable и enable

Вы можете использовать директиву для отключения / включения элемента управления, подписаться на valueChanges или, если вы используете mat-select, использовать event selectionChange, например (*):

<mat-select formControlName="authTypeName"
    (selectionChange)="addAuthorityForm.get('authDescription')
                 [$event.value=='EWO'?'enable':'disable']()">
    <mat-option *ngFor="let at of authTypes" [value]="at.authTypeName">
       {{at.authTypeName}}
    </mat-option>
 </mat-select>

Я делаю простой стек

(*) не забывайте, что при создании группы форм создавайте элемент управления включенным или отключенным

Обновите, если мы не хотим отключать элемент управления, на самом деле нам нужно создать настраиваемый элемент проверки формы.

Мы можем сделать настраиваемую проверку элемента управления формой над FormControl, FormGroup или FormArray. В этом случае мы выбираем сделать это над FromControl. Но мы должны принять во внимание, что если мы изменимauthTypeName, нам нужно указать Angular, что проверяет, authDescription подтверждается или нет

<mat-select formControlName="authTypeName" 
   (selectionChange)="form.get('authDescription').updateValueAndValidity()">
      ...
</mat-select>

Ну, наша настраиваемая проверка формы. Поскольку у нас есть "control", в control.parent"есть форма", так что это так просто, как

  requiredIf(requiredValue:string){
    return (control:FormControl)=>{
      const form=control.parent;
      if (form)
      {
        //really we need decalre controlDescription, it's the
        //same of "control"
        const controlDescription=form.get('authDescription')
        const controlTypeName=form.get('authTypeName')
        if (controlTypeName && controlDescription && 
            controlTypeName.value==requiredValue && !controlDescription.value)
           return {required:true}
      }
      return null
    }
  }

И мы можем написать

  form=new FormGroup({
    authDescription:new FormControl(null,this.requiredIf('EWO')),
    authTypeName:new FormControl('EWO')
  })

Посмотрите, что значение 'EWO' фиксировано при объявлении formGroup

новый stackblitz

Я не уверен, что вы имели в виду, когда говорили: "Но не должно отображаться никаких ошибок, если в раскрывающемся списке" Тип полномочий "выбрана опция" EWO "". Я предполагаю, что он не должен показывать никаких ошибок, если для этого сценария не введен "Authority# (Alpha)".

Там может быть лучшее решение, но вот подход, который я использую в своих проектах. Вы можете поместить этот блок после инициализации формы, чтобы форма уже имела эти элементы управления типом авторизации и номером авторизации для доступа:

this.addAuthorityForm.get('authTypeName').valueChanges.subscribe((newValue) => {
    const authNumber = this.addAuthorityForm.get('authNumber');

    // I don't know the exact structure of the authTypeName so you can debug and change the condition if needed
    if (newValue === 'EWO') { 
        authNumber.setValidators([Validators.required, Validators.maxLength(20), Validators.pattern(this.alphabeticRegex)]);
    } else {
        authNumber.setValidators([Validators.maxLength(20), Validators.pattern(this.alphabeticRegex)]);
    }
    authNumber.updateValueAndValidity();
})

По сути, это переназначает валидаторы для номера аутентификации при изменении типа аутентификации, добавляя необходимые валидаторы. я используюValidators.required потому что он предоставляется из коробки, но если вы хотите сделать его более индивидуальным, у вас может быть что-то вроде этого:

...
authNumber.setValidators([(c: FormControl) => {
    return c.value ? null : {required: {valid: false}};
}, Validators.maxLength(20), Validators.pattern(this.alphabeticRegex)]);
...

В updateValueAndValidity Метод заключается в том, чтобы повторно проверить поле, когда пользователь переключает тип аутентификации.

Другие вопросы по тегам