【问题标题】:how to make a custom validator in angular to check a form field based on the other form field?如何以角度制作自定义验证器以根据其他表单字段检查表单字段?
【发布时间】:2020-12-09 02:21:23
【问题描述】:

组件的打字稿是:

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>

这是我的添加对话框: The Add dialog box

如何添加自定义验证,以便在“权限类型”下拉列表中选择“EWO”选项时,如果未输入“权限# (Alpha)”,则会显示错误。但是,如果为“授权类型”下拉菜单选择了“EWO”选项,它应该不会显示任何错误。

【问题讨论】:

    标签: angular validation mat-error


    【解决方案1】:

    如果您不选择 EWO,您可以禁用“授权”,因此 Angular 不会检查是否需要。要禁用/启用您需要使用方法disable and enable

    您可以使用directive to disable/enable 控件,订阅valueChanges,或者,当您使用mat-select 时,使用事件 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>
    

    我发了一个simple stackblitz

    (*)别忘了,在创建formgroup的时候,要创建控件启用或禁用

    更新如果我们不想禁用该控件,我们真的需要创建一个自定义表单控件验证。

    我们可以对 FormControl、FormGroup 或 FormArray 进行自定义表单控件验证。在这种情况下,我们选择 make it over FromControl。但我们需要考虑的是,我们是否更改了authTypeName,我们需要向 Angular 指示检查authDescription 是否有效

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

    好吧,我们的自定义表单验证。因为我们有“控件”,所以在 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')
      })
    

    在声明formGroup时看到'EWO'的值是固定的

    new stackblitz

    【讨论】:

    • 感谢您的回答。这本来可以,但是无论您选择什么,我都需要始终启用该字段。
    • @ES,如果你不想“禁用”,真的需要一个自定义的 FormValidation。检查更新的答案和新的 stackblitz
    【解决方案2】:

    我不确定您所说的“但如果为 'Authority Type' 下拉菜单选择了 '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 方法是在用户切换授权类型时重新验证该字段。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-18
      • 1970-01-01
      • 2022-01-02
      • 1970-01-01
      相关资源
      最近更新 更多