0

The typescript for the component is:

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;
   }


}

The html code is:

<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>

This is my add dialog box: The Add dialog box

How to add a custom validation so that if 'EWO' option is chosen for the 'Authority Type' dropdown, it would show an error if the 'Authority# (Alpha)' is not entered. But it should not show any error if the 'EWO' option is chosen for the 'Authority Type' dropdown.

4

2 回答 2

0

You can disable the "Authority" if you don't choose EWO, so Angular not check if is required or not. To disable/enable you need use the methods disable and enable

You can use a directive to disable/enable the control, subscribe to valueChanges or, as you're using a mat-select, use the event selectionChange like (*):

<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>

I make a simple stackblitz

(*) don't forget, when create the formgroup, create the control enabled or disabled

Update if we don't want disable the control, really we need create a custom Form control Validation.

We can make a custom form Control Validation over a FormControl, a FormGroup or a FormArray. In this case we choose make it over a FromControl. But we need take account that, is we change the authTypeName, we need indicate to Angular that check if the authDescription is validate or not

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

Well, our custom Form validation. As we has the "control", in control.parent" we has the "form", so it's so easy like

  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
    }
  }

And we can write

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

See that the value 'EWO' is fixed when declare the formGroup

the new stackblitz

于 2020-08-19T20:58:47.400 回答
0

I'm not sure what you meant when you say "But it should not show any error if the 'EWO' option is chosen for the 'Authority Type' dropdown.". I'll assume that it should not show any error if the 'Authority# (Alpha)' is not entered for that scenario.

There could be better solution out there but here's the approach that I use in my projects. You can put this block after form initialization so the form already has these auth type and auth number controls to access:

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();
})

Basically, what this does is reassign the validators for the auth number when the auth type change by adding the required validators. I use Validators.required because it's provided out of the box but if you want to make it more custom, you can have something like this:

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

The updateValueAndValidity method is to revalidate the field when user switches the auth type.

于 2020-08-19T23:14:43.520 回答