Skip to content

Commit

Permalink
fix(stepper): unable to skip optional steps in linear stepper (#9245)
Browse files Browse the repository at this point in the history
Fixes users not being allowed to skip optional invalid steps inside of a linear stepper.

Fixes #9239.
  • Loading branch information
crisbeto authored and jelbourn committed Jan 29, 2018
1 parent c3ec94d commit 517ea57
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 18 deletions.
3 changes: 2 additions & 1 deletion src/cdk/stepper/stepper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,8 @@ export class CdkStepper implements OnDestroy {
if (this._linear && index >= 0) {
return steps.slice(0, index).some(step => {
const control = step.stepControl;
return control ? (control.invalid || control.pending) : !step.completed;
const isIncomplete = control ? (control.invalid || control.pending) : !step.completed;
return isIncomplete && !step.optional;
});
}

Expand Down
25 changes: 8 additions & 17 deletions src/lib/stepper/stepper.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -780,24 +780,26 @@ function assertEditableStepChange(fixture: ComponentFixture<any>) {
}

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

testComponent.oneGroup.get('oneCtrl')!.setValue('input');
testComponent.twoGroup.get('twoCtrl')!.setValue('input');
testComponent.validationTrigger.next();
stepperComponent.selectedIndex = 2;
fixture.detectChanges();

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

let nextButtonNativeEl = fixture.debugElement
const nextButtonNativeEl = fixture.debugElement
.queryAll(By.directive(MatStepperNext))[2].nativeElement;
nextButtonNativeEl.click();
fixture.detectChanges();
Expand All @@ -812,15 +814,7 @@ function assertOptionalStepValidity(testComponent:

expect(testComponent.threeGroup.get('threeCtrl')!.valid).toBe(false);
expect(stepperComponent.selectedIndex)
.toBe(2, 'Expected selectedIndex to remain unchanged when optional step input is invalid.');

testComponent.threeGroup.get('threeCtrl')!.setValue('valid');
nextButtonNativeEl.click();
fixture.detectChanges();

expect(testComponent.threeGroup.get('threeCtrl')!.valid).toBe(true);
expect(stepperComponent.selectedIndex)
.toBe(3, 'Expected selectedIndex to change when optional step input is valid.');
.toBe(3, 'Expected selectedIndex to change when optional step input is invalid.');
}

/** Asserts that step header set the correct icon depending on the state of step. */
Expand All @@ -841,10 +835,7 @@ function assertCorrectStepIcon(fixture: ComponentFixture<any>,
function asyncValidator(minLength: number, validationTrigger: Observable<any>): AsyncValidatorFn {
return (control: AbstractControl): Observable<ValidationErrors | null> => {
return validationTrigger.pipe(
map(() => {
const success = control.value && control.value.length >= minLength;
return success ? null : { 'asyncValidation': {}};
}),
map(() => control.value && control.value.length >= minLength ? null : {asyncValidation: {}}),
take(1)
);
};
Expand Down

0 comments on commit 517ea57

Please sign in to comment.