diff --git a/src/cdk/stepper/stepper.md b/src/cdk/stepper/stepper.md
index 6d480d154e6f..2cc43082e459 100644
--- a/src/cdk/stepper/stepper.md
+++ b/src/cdk/stepper/stepper.md
@@ -45,6 +45,10 @@ There are two button directives to support navigation between different steps:
`CdkStepperNext` and `CdkStepperPrevious`. When placed inside of a step, these will automatically
add click handlers to advance or rewind the workflow, respectively.
+### Resetting a stepper
+If you want to reset a stepper to its initial state, you can use the `reset` method. Note that
+resetting it will call `reset` on the underlying form control which clears the value.
+
### Keyboard interaction
- LEFT_ARROW: Focuses the previous step header
- RIGHT_ARROW: Focuses the next step header
diff --git a/src/cdk/stepper/stepper.ts b/src/cdk/stepper/stepper.ts
index 3d9a3f429055..526175a2c88e 100644
--- a/src/cdk/stepper/stepper.ts
+++ b/src/cdk/stepper/stepper.ts
@@ -123,6 +123,16 @@ export class CdkStep implements OnChanges {
this._stepper.selected = this;
}
+ /** Resets the step to its initial state. Note that this includes resetting form data. */
+ reset(): void {
+ this.interacted = false;
+ this.completed = false;
+
+ if (this.stepControl) {
+ this.stepControl.reset();
+ }
+ }
+
ngOnChanges() {
// Since basically all inputs of the MatStep get proxied through the view down to the
// underlying MatStepHeader, we have to make sure that change detection runs correctly.
@@ -208,6 +218,13 @@ export class CdkStepper implements OnDestroy {
this.selectedIndex = Math.max(this._selectedIndex - 1, 0);
}
+ /** Resets the stepper to its initial state. Note that this includes clearing form data. */
+ reset(): void {
+ this.selectedIndex = 0;
+ this._steps.forEach(step => step.reset());
+ this._stateChanged();
+ }
+
/** Returns a unique id for each step label element. */
_getStepLabelId(i: number): string {
return `cdk-step-label-${this._groupId}-${i}`;
diff --git a/src/demo-app/stepper/stepper-demo.html b/src/demo-app/stepper/stepper-demo.html
index 0dd4274921ba..244f47772e75 100644
--- a/src/demo-app/stepper/stepper-demo.html
+++ b/src/demo-app/stepper/stepper-demo.html
@@ -2,7 +2,7 @@
Linear Vertical Stepper Demo using a single form
Linear Horizontal Stepper Demo using a different form for each step
-
+
diff --git a/src/lib/stepper/stepper.spec.ts b/src/lib/stepper/stepper.spec.ts
index 5dd85b3bc260..a533d15336d0 100644
--- a/src/lib/stepper/stepper.spec.ts
+++ b/src/lib/stepper/stepper.spec.ts
@@ -250,6 +250,10 @@ describe('MatHorizontalStepper', () => {
expect(stepper.selectedIndex).toBe(1);
});
+
+ it('should be able to reset the stepper to its initial state', () => {
+ assertLinearStepperResetable(fixture);
+ });
});
});
@@ -413,6 +417,10 @@ describe('MatVerticalStepper', () => {
it('should be able to move to next step even when invalid if current step is optional', () => {
assertOptionalStepValidity(testComponent, fixture);
});
+
+ it('should be able to reset the stepper to its initial state', () => {
+ assertLinearStepperResetable(fixture);
+ });
});
});
@@ -850,6 +858,49 @@ function asyncValidator(minLength: number, validationTrigger: Observable):
};
}
+
+/** Asserts that a stepper can be reset. */
+function assertLinearStepperResetable(
+ fixture: ComponentFixture) {
+
+ const testComponent = fixture.componentInstance;
+ const stepperComponent = fixture.debugElement.query(By.directive(MatStepper)).componentInstance;
+ const steps = stepperComponent._steps.toArray();
+
+ testComponent.oneGroup.get('oneCtrl')!.setValue('value');
+ fixture.detectChanges();
+
+ stepperComponent.next();
+ fixture.detectChanges();
+
+ stepperComponent.next();
+ fixture.detectChanges();
+
+ expect(stepperComponent.selectedIndex).toBe(1);
+ expect(steps[0].interacted).toBe(true);
+ expect(steps[0].completed).toBe(true);
+ expect(testComponent.oneGroup.get('oneCtrl')!.valid).toBe(true);
+ expect(testComponent.oneGroup.get('oneCtrl')!.value).toBe('value');
+
+ expect(steps[1].interacted).toBe(true);
+ expect(steps[1].completed).toBe(false);
+ expect(testComponent.twoGroup.get('twoCtrl')!.valid).toBe(false);
+
+ stepperComponent.reset();
+ fixture.detectChanges();
+
+ expect(stepperComponent.selectedIndex).toBe(0);
+ expect(steps[0].interacted).toBe(false);
+ expect(steps[0].completed).toBe(false);
+ expect(testComponent.oneGroup.get('oneCtrl')!.valid).toBe(false);
+ expect(testComponent.oneGroup.get('oneCtrl')!.value).toBeFalsy();
+
+ expect(steps[1].interacted).toBe(false);
+ expect(steps[1].completed).toBe(false);
+ expect(testComponent.twoGroup.get('twoCtrl')!.valid).toBe(false);
+}
+
+
@Component({
template: `
diff --git a/src/material-examples/stepper-overview/stepper-overview-example.html b/src/material-examples/stepper-overview/stepper-overview-example.html
index 2e4b12c42600..538072ed0372 100644
--- a/src/material-examples/stepper-overview/stepper-overview-example.html
+++ b/src/material-examples/stepper-overview/stepper-overview-example.html
@@ -1,6 +1,6 @@
-
+