简体   繁体   中英

Angular - How to Validate each step in Angular Material stepper

In Angular-12, I am implementing Material Stepper. And it has two (2) steps:

Component:

 export class SignupCompanyComponent implements OnInit { isLinear = true; isLoading = false; companySetupForm!: FormGroup; companyForm!: FormGroup; idForm!: FormGroup; ngOnInit() { this.companyForm = this.fb.group({ companyName: ['', [Validators.required, Validators.minLength(3), Validators.maxLength(100)]] }); this.idForm = this.fb.group({ registrationNumber: ['', [Validators.required, Validators.maxLength(100)]], }); } get fc() { return this.companyForm.controls; }; get fi() { return this.idForm.controls; }; onSubmit() {} }

HTML:

 <mat-horizontal-stepper [linear]="isLinear" #stepper labelPosition="bottom"> <mat-step [stepControl]="companyForm"> <form [formGroup]="companyForm"> <ng-template matStepLabel matStepperIcon="phone">Company Info</ng-template> <div class="col-12 col-md-12"> <div class="form-group"> <label for="name">Company Name:<span style="color:red;">*</span></label>} <input type="text" formControlName="companyName" placeholder="Company Name" class="form-control" required/> </div> <div *ngIf="fc.companyName.touched && fc.companyName.invalid"> <div *ngIf="fc.companyName.hasError('required')"> <div class="text-danger"> Company Name is required! </div> </div> <div *ngIf="fc.companyName.hasError('minlength')"> <div class="text-danger"> Company Name cannot be less than 3 characters! </div> </div> <div *ngIf="fc.companyName.hasError('maxlength')"> <div class="text-danger"> Company Name cannot be more than 100 characters! </div> </div> </div> </div> <div class="card-footer"> <button mat-raised-button color="primary" matStepperNext>Next</button> </div> </form> </mat-step> <mat-step [stepControl]="idForm"> <form [formGroup]="idForm"> <ng-template matStepLabel>Company ID</ng-template> <div class="col-12 col-md-4"> <div class="form-group"> <label for="registration_number">Registration Number:<span style="color:red;">*</span></label> <input type="text" formControlName="registrationNumber" placeholder="Registration Number" class="form-control" required/> </div> <div *ngIf="fi.registrationNumber.touched && fi.registrationNumber.invalid"> <div *ngIf="fi.registrationNumber.hasError('required')"> <div class="text-danger"> Company Reg. No. is required! </div> </div> <div *ngIf="fi.registrationNumber.hasError('maxlength')"> <div class="text-danger"> Company Reg. No. cannot be more than 100 characters! </div> </div> </div> </div> <div class="card-footer"> <button mat-raised-button color="black" matStepperPrevious>Back</button> &nbsp; <button mat-raised-button color="success" [disabled]="isLoading" type="submit" (click)="onSubmit()"> <span *ngIf="isLoading" class="spinner-border spinner-border-sm mr-1"></span> Submit </button> &nbsp; <button mat-raised-button color="warn" (click)="stepper.reset()">Reset</button> </div> </mat-step> </mat-horizontal-stepper>

When each formControl is touched, the Material Stepper works fine. It displays the error immediately. But when Next Button is clicked no data is filled in Step1 (companyForm), though it didn't move to the next step or form, but no error is displayed.

I want it to validate each step and display as it is done when each form control is touched.

How do I achieve this?

Thanks

Two things I do is set field validation to onBlur like;

this.companyForm = this.fb.group({
      companyName: ['',
                   [Validators.required,
                    Validators.minLength(3),
                    Validators.maxLength(100)]]
    },
    { updateOn: "blur" });

...and personally I don't like to allow continuing until the required fields are valid so I set the stepper button to disabled until it is like;

<button mat-raised-button
        color="primary"
        matStepperNext
        [disabled]="companyForm.status != 'VALID'">
   Next
</button>

Or definitely see Mr. Manhattan's comment below to validate the form at the end, which you can accomplish the same thing by changing the { updateOn: "blur" } above from blur to submit

Material doesn't seem to mark the form as touched, so i'd rebind the button:

<button mat-raised-button color="primary" (click)="onFirstStepDone()">Next</button>

in the component, you'll need a reference to the stepper:

@ViewChild('stepper') stepper: MatHorizontalStepper;

onFirstStepDone() {
   if(!this.companyForm .valid) {
       // this should make all invalid fields light up in red
       this.companyForm.markAllAsTouched();
       return;
   }
   this.stepper.next();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM