mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
feat(stepper): add the ability to reset a stepper (#8623)
Allows for the user to reset a stepper to its initial state by calling the `reset` method. Relates to #7700.
This commit is contained in:
committed by
Jeremy Elbourn
parent
c8743e70de
commit
a6f9fc25d2
@@ -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
|
||||
- <kbd>LEFT_ARROW</kbd>: Focuses the previous step header
|
||||
- <kbd>RIGHT_ARROW</kbd>: Focuses the next step header
|
||||
|
||||
@@ -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.
|
||||
@@ -209,6 +219,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}`;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<h3>Linear Vertical Stepper Demo using a single form</h3>
|
||||
<form [formGroup]="formGroup">
|
||||
<mat-vertical-stepper formArrayName="formArray" [linear]="!isNonLinear">
|
||||
<mat-vertical-stepper #linearVerticalStepper="matVerticalStepper" formArrayName="formArray" [linear]="!isNonLinear">
|
||||
<mat-step formGroupName="0" [stepControl]="formArray?.get([0])">
|
||||
<ng-template matStepLabel>Fill out your name</ng-template>
|
||||
<mat-form-field>
|
||||
@@ -38,13 +38,14 @@
|
||||
Everything seems correct.
|
||||
<div>
|
||||
<button mat-button>Done</button>
|
||||
<button type="button" mat-button (click)="linearVerticalStepper.reset()">Reset</button>
|
||||
</div>
|
||||
</mat-step>
|
||||
</mat-vertical-stepper>
|
||||
</form>
|
||||
|
||||
<h3>Linear Horizontal Stepper Demo using a different form for each step</h3>
|
||||
<mat-horizontal-stepper [linear]="!isNonLinear">
|
||||
<mat-horizontal-stepper #linearHorizontalStepper="matHorizontalStepper" [linear]="!isNonLinear">
|
||||
<mat-step [stepControl]="nameFormGroup">
|
||||
<form [formGroup]="nameFormGroup">
|
||||
<ng-template matStepLabel>Fill out your name</ng-template>
|
||||
@@ -82,6 +83,7 @@
|
||||
Everything seems correct.
|
||||
<div>
|
||||
<button mat-button>Done</button>
|
||||
<button type="button" mat-button (click)="linearHorizontalStepper.reset()">Reset</button>
|
||||
</div>
|
||||
</form>
|
||||
</mat-step>
|
||||
|
||||
@@ -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<any>):
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/** Asserts that a stepper can be reset. */
|
||||
function assertLinearStepperResetable(
|
||||
fixture: ComponentFixture<LinearMatHorizontalStepperApp|LinearMatVerticalStepperApp>) {
|
||||
|
||||
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: `
|
||||
<mat-horizontal-stepper>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<button mat-raised-button (click)="isLinear = true" id="toggle-linear">Enable linear mode</button>
|
||||
|
||||
<mat-horizontal-stepper [linear]="isLinear">
|
||||
<mat-horizontal-stepper [linear]="isLinear" #stepper="matHorizontalStepper">
|
||||
<mat-step [stepControl]="firstFormGroup">
|
||||
<form [formGroup]="firstFormGroup">
|
||||
<ng-template matStepLabel>Fill out your name</ng-template>
|
||||
@@ -29,6 +29,7 @@
|
||||
You are now done.
|
||||
<div>
|
||||
<button mat-button matStepperPrevious>Back</button>
|
||||
<button mat-button (click)="stepper.reset()">Reset</button>
|
||||
</div>
|
||||
</mat-step>
|
||||
</mat-horizontal-stepper>
|
||||
|
||||
Reference in New Issue
Block a user