I am using a mat-stepper for a dialog that is used both for creating new and for editing existing entities of a specific type. The stepper consists of four steps. Each of the first three steps contain a form for entering data while the last step is only a summary/overview of the data which was entered via the first three steps.
I only want to allow the user to go to the last step if he/she entered valid data in all three steps. To do this, I added the linear
attribute to the stepper to force the user to go through each step. This works perfectly fine when the user is creating a new entity via the dialog. However, when editing an existing entity, it is not possible to for example go directly to step 3 before at least clicking on step 2. When opening the dialog in editing mode, I programmatically fill all of the fields in the steps with the data of the existing entity, so I want to allow the user to go to any of the steps directly, as long as valid data is entered in the currently visible step. Here is a stackblitz showing the problem:
stackblitz
Despite all fields being already filled programmatically, I cannot for example directly go to step 3 or 4 before clicking on the previous steps.
My first attempt to resolve this was to remove the linear
attribute when the dialog is opened in editing mode. While this has the desired effect, it also allows the user to clear some of the fields in a step and then directly go to the last step, which I do not want to allow because the last step should only be reachable if all previous steps are completely filled with valid data.
Is there a way to achieve this behaviour in a mat-stepper? If my problem isn't clear, please let me know and I will try my best to describe it in more detail.
This would be easier to answer if you included some code, or better yet, a stack blitz. But in any case, can't you simply set the "linear" attribute programatically?, something like:
<mat-stepper [linear]="this.formGroup.valid" #stepper>
-- EDIT --
After you put up your stackblitz, my suggestion remains the same – the only issue is you have three separate forms. So just to make things easy I've made a globalForm that consists of the other three:
globalForm = new FormGroup({
form1: this.form1,
form2: this.form2,
form3: this.form3
});
Then in the html I assign linear to !globalForm.valid
<mat-stepper [linear]="!globalForm.valid" #stepper>
Alternatively you could skip the global form and just use
<mat-stepper [linear]="!(form1.valid && form2.valid && form3.valid)" #stepper>
It comes down to preference I guess.
In any case, you'll see now that you can jump to the end at the start, but if you empty one of the fields, you cannot progress until you add a value to it.
Here is the fork:
https://stackblitz.com/edit/angular-ivy-2mb2b8?file=src%2Fapp%2Fapp.component.html