Reputation: 209
I have 4 mat-step
in mat-vertical-stepper.
I want to disable 2nd,3rd & 4th mat-step
until the 1st mat-step
's all fields covered.
I tried:
<mat-step label="Step 1">
<!-- some codes-->
</mat-step>
In Step 1 I have a next button and this button is disabled till all fields are covered.
<button mat-raised-button color="primary" style="float:right"
[disabled]="!DetailsForm.valid" (click)="step2.disabled = false">Next</button>
Next is STEP 2:
<mat-step label="Step 2" [disabled]="step2.disabled">
it shows an error "disabled is not a part of mat-step
".
Like this, rest two mat-step
are there. I want to disable 2nd,3rd,4th mat-step
.
In below case, how can I use linear
?
<mat-vertical-stepper #stepper>
<mat-step label="General Details">
<h4> First Name </h4>
</mat-step>
<mat-step label="Education">
<h4>Highest Education </h4>
</mat-step>
</mat-vertical-stepper>
And,
<div class="col-md-9 col-lg-9">
<form [formGroup]="generalDetailsForm">
<div class="row">
<div class="col-md-5 col-lg-5">
<mat-form-field class="example-full-width">
<input matInput placeholder="First Name" [(ngModel)]="firstName">
</mat-form-field>
</div>
</div>
</form>
</div>
Upvotes: 13
Views: 32209
Reputation: 39
Use a FormGroup just to allow next step.
Example: .ts
this.clientForm = this.formBuilder.group({
client: [this.client, Validators.required],
});
this.clientConfigForm = this.formBuilder.group({
formOk: ['', Validators.required],
clientForm: this.clientForm
});
.html
<mat-stepper orientation="vertical" linear>
<mat-step [stepControl]="clientConfigForm">
<form [formGroup]="clientForm" (ngSubmit)="clientConfigForm.controls.formOk.setValue('ok')">
<mat-form-field appearance="outline">
<input type="text" matInput maxlength="10" formControlName="client" class="form-control">
</mat-form-field>
<button mat-raised-button color="primary"
[disabled]="!clientForm.valid">
Next
</button>
</form>
</mat-step>
<mat-step>
...
</mat-step>
Upvotes: 0
Reputation: 31
Using @Hypenate's answer, I just wanted to force the user to stay at the current step while the formGroup (connedted to the current step) is INVALID.
So I made a css definition in styles.css:
.mat-element-notclickable{
pointer-events: none;
cursor: not-allowed;
opacity: 0.5;
color: #cccccc;
}
than in ngOnInit I just subscribe to the formGroup's statusChange and disable all the steps as needed:
ngOnInit() {
this.formGroup.statusChanges.subscribe( newStatus => {
if( newStatus === 'VALID') {
Array.from(document.getElementsByClassName('mat-step-header')).forEach(element => {
element.classList.remove('mat-element-notclickable')
});
} else {
Array.from(document.getElementsByClassName('mat-step-header')).forEach(element => {
element.classList.add('mat-element-notclickable')
})
}
})
}
(of course, you could just use the header container, and use only one .classList.add and remove, but in other places I will need to enable/disable steps separately)
Upvotes: 0
Reputation: 2064
I had to disable a step depending on a condition.
I created a directive and queried the dom to add a class.
stylesheet:
.mat-step-disabled {
pointer-events: none;
opacity: 0.5;
color: #cccccc;
}
Directive
@Directive({
selector: '[step-disable]'
})
export class StepDisableDirective implements OnChanges {
@Input() public isDisabled: boolean = true;
public ngOnChanges(changes: SimpleChanges): void {
this.isDisabled? this.disable() : this.enable();
}
private enable(): void {
const el:HTMLElement = this.getElement();
el.classList.add('mat-step-disabled');
}
private disable(): void {
const el:HTMLElement = this.getElement();
el.classList.remove('mat-step-disabled');
}
private getElement(): HTMLElement {
const elements: HTMLCollectionOf<Element> = document.getElementsByClassName(mat-step-header);
const matStepHeader = elements[0] as HTMLElement; // Take the first step, you want to pass your index via an Input parameter
return matStepHeader;
}
}
Module
@NgModule({
declarations: [
StepDisableDirective
]
})
export class AppModule{ }
HTML
Set the directive and it's input parameter
<mat-step step-disable [isDisabled]="true" label="Foo">
Upvotes: 4
Reputation: 63
The solution from @delpo and @Matvii should fit your needs.
<mat-vertical-stepper #stepper [linear]="true">
<mat-step
state="first"
[completed]="formGroup.valid"
[editable]="true">
</mat-step>
<mat-step state="final">
</mat-step>
</mat-vertical-stepper>
This can be achieved by using [linear]="true" and disabling the next step with [completed]="formGroup.valid" by passing the validity of your FormGroup, so whenever the FormGroup is Valid next step should be enabled/should be able to proceed.
Upvotes: 6
Reputation: 940
Step-1: Component.ts
stepDisabled: boolean = true;
step-2: Component.css
::ng-deep .mat-step-header[aria-labelledby="disabled_Resi"] {
pointer-events: none !important;
cursor: not-allowed;
}
step-3: Component.html
<mat-step [aria-labelledby]="stepDisabled ? 'disabled_Resi' : null" [stepControl]="ResidentalAddressFG"></mat-step>
step:4
<button mat-stroked-button (click)="stepDisabled = !stepDisabled">{{stepDisabled ? 'Enable' : 'Disable'}} Step</button>
Upvotes: 4
Reputation: 161
<mat-horizontal-stepper #stepper [linear]="true">
<mat-step [completed]="false">
<!-- set completed = false to disable next step -->
</mat-step>
<mat-step>
this step would be disable
</mat-step>
</mat-horizontal-stepper>
Upvotes: 14
Reputation: 61
if you want to disable step 2 you should use [completed] on step 1, at the same time setting [stepControl] to null, because [stepControl] takes precedence over [completed]
<mat-horizontal-stepper #stepper [linear]="true">
<!-- step1 -->
<mat-step
[stepControl]="shouldNextStepBeDisabled ? null : formGroup"
[completed]="shouldNextStepBeDisabled ? false : formGroup.valid">
</mat-step>
....
</mat-horizontal-stepper>
Upvotes: 4
Reputation: 239
For anyone seeing this.
I resolved this with linear
completed
attributes.
<mat-horizontal-stepper #stepper [linear]="true">
<mat-step state="state_1" label="label" [completed]="condition">
</mat-step>
....
</mat-horizontal-stepper>
Use the completed attribute to mark the step as 'completed'
From the docs:
Alternatively, if you don't want to use the Angular forms, you can pass in the completed property to each of the steps which won't allow the user to continue until it becomes true. Note that if both completed and stepControl are set, the stepControl will take precedence.
https://material.angular.io/components/stepper/overview
Edit: added example
Upvotes: 1
Reputation: 209
in mat-step
use [stepControl]="formName"
and in .ts
do validation of the form.
Using only linear
won't help. I was doing wrong. I did not use [stepControl]
Upvotes: 2
Reputation: 9839
mat-vertical-stepper
has no property disabled as the exception message says.
try setting <mat-vertical-stepper [linear]="true">
after that you need to handle the visibilty of the button as you did. a button has the disabled property.
Upvotes: 1