The following approach works for me:
- Make mat-stepper linear
<mat-vertical-stepper [linear]="true" #stepper>
....
</mat-vertical-stepper>
- Make steps not editable, not optional and associate a stepControl with a FormGroup
<mat-step [editable]="false" [optional]="false" [stepControl]="desiredServiceFormGroup">
<form [formGroup]="desiredServiceFormGroup">
...
</form>
</mat-step>
- add controls to your FormGroup for your form items described in HTML and add a extra control. For an inexistent form control on your html code (in this example, I added the control called 'x', inexistent in my html code)
ngOnInit() {
this.desiredServiceFormGroup = this.formBuilder.group({
desiredTarget: [ '', Validators.required],
paymentAgreed: ['', Validators.required],
...
x: ['', Validators.required]
});
}
With this extra validator, your stepControl will always be false.
When stepControl is false, step is not optional, not editable and stepper is linear. Direct clicks on step headers do not change the current step.
- button will not be associated with formControl (at that case, it will be always disabled). In my case, I verify each Form item manually
<button [disabled]="desiredTarget == null || !paymentAgreed" (click)="createVerification(desiredTarget.targetId, stepper)">NEXT</button>
- make your needed operations and when it's done, remove the extra control that makes your form control always invalid. Go programmatically to next step.
async createVerification(targetId: number, stepper?: MatStepper) {
this.verification = await this.dataService.createVerification(targetId);
if (stepper !== undefined) {
this.desiredServiceFormGroup.removeControl('x');
stepper.next();
}
}
- If you need to make a reset of stepper, add the extra control to FormControl
reset(stepper?: MatStepper) {
this.desiredServiceFormGroup.addControl('x', new FormControl('', [Validators.required]));
stepper.reset();
}