Skip to content

Commit 9dba30b

Browse files
crisbetojelbourn
authored andcommitted
fix(stepper): unable to skip optional steps in linear stepper (#9245)
Fixes users not being allowed to skip optional invalid steps inside of a linear stepper. Fixes #9239.
1 parent 7c78c93 commit 9dba30b

File tree

2 files changed

+10
-18
lines changed

2 files changed

+10
-18
lines changed

src/cdk/stepper/stepper.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,8 @@ export class CdkStepper implements OnDestroy {
322322
if (this._linear && index >= 0) {
323323
return steps.slice(0, index).some(step => {
324324
const control = step.stepControl;
325-
return control ? (control.invalid || control.pending) : !step.completed;
325+
const isIncomplete = control ? (control.invalid || control.pending) : !step.completed;
326+
return isIncomplete && !step.optional;
326327
});
327328
}
328329

src/lib/stepper/stepper.spec.ts

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -811,24 +811,26 @@ function assertEditableStepChange(fixture: ComponentFixture<any>) {
811811
}
812812

813813
/**
814-
* Asserts that it is possible to skip an optional step in linear stepper if there is no input
815-
* or the input is valid.
814+
* Asserts that it is possible to skip an optional step in linear
815+
* stepper if there is no input or the input is invalid.
816816
*/
817817
function assertOptionalStepValidity(testComponent:
818818
LinearMatHorizontalStepperApp | LinearMatVerticalStepperApp,
819819
fixture: ComponentFixture<any>) {
820-
let stepperComponent = fixture.debugElement.query(By.directive(MatStepper)).componentInstance;
820+
const stepperComponent: MatStepper = fixture.debugElement
821+
.query(By.directive(MatStepper)).componentInstance;
821822

822823
testComponent.oneGroup.get('oneCtrl')!.setValue('input');
823824
testComponent.twoGroup.get('twoCtrl')!.setValue('input');
824825
testComponent.validationTrigger.next();
825826
stepperComponent.selectedIndex = 2;
826827
fixture.detectChanges();
827828

829+
expect(stepperComponent._steps.toArray()[2].optional).toBe(true);
828830
expect(stepperComponent.selectedIndex).toBe(2);
829831
expect(testComponent.threeGroup.get('threeCtrl')!.valid).toBe(true);
830832

831-
let nextButtonNativeEl = fixture.debugElement
833+
const nextButtonNativeEl = fixture.debugElement
832834
.queryAll(By.directive(MatStepperNext))[2].nativeElement;
833835
nextButtonNativeEl.click();
834836
fixture.detectChanges();
@@ -843,15 +845,7 @@ function assertOptionalStepValidity(testComponent:
843845

844846
expect(testComponent.threeGroup.get('threeCtrl')!.valid).toBe(false);
845847
expect(stepperComponent.selectedIndex)
846-
.toBe(2, 'Expected selectedIndex to remain unchanged when optional step input is invalid.');
847-
848-
testComponent.threeGroup.get('threeCtrl')!.setValue('valid');
849-
nextButtonNativeEl.click();
850-
fixture.detectChanges();
851-
852-
expect(testComponent.threeGroup.get('threeCtrl')!.valid).toBe(true);
853-
expect(stepperComponent.selectedIndex)
854-
.toBe(3, 'Expected selectedIndex to change when optional step input is valid.');
848+
.toBe(3, 'Expected selectedIndex to change when optional step input is invalid.');
855849
}
856850

857851
/** Asserts that step header set the correct icon depending on the state of step. */
@@ -872,10 +866,7 @@ function assertCorrectStepIcon(fixture: ComponentFixture<any>,
872866
function asyncValidator(minLength: number, validationTrigger: Observable<any>): AsyncValidatorFn {
873867
return (control: AbstractControl): Observable<ValidationErrors | null> => {
874868
return validationTrigger.pipe(
875-
map(() => {
876-
const success = control.value && control.value.length >= minLength;
877-
return success ? null : { 'asyncValidation': {}};
878-
}),
869+
map(() => control.value && control.value.length >= minLength ? null : {asyncValidation: {}}),
879870
take(1)
880871
);
881872
};

0 commit comments

Comments
 (0)