From a93407487a2002565bb856fe9853d090df879842 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Wed, 25 Oct 2017 21:09:51 +0200 Subject: [PATCH] fix(stepper): error when selectedIndex is pre-set Fixes an error that is thrown if the `selectedIndex` is set before the steps are initialized. Fixes #8031. --- src/cdk/stepper/stepper.ts | 25 ++++++++++++++++--------- src/lib/stepper/stepper.spec.ts | 26 ++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/src/cdk/stepper/stepper.ts b/src/cdk/stepper/stepper.ts index 9ce5937309ca..e126102e95de 100644 --- a/src/cdk/stepper/stepper.ts +++ b/src/cdk/stepper/stepper.ts @@ -148,13 +148,17 @@ export class CdkStepper { @Input() get selectedIndex() { return this._selectedIndex; } set selectedIndex(index: number) { - if (this._anyControlsInvalid(index) - || index < this._selectedIndex && !this._steps.toArray()[index].editable) { - // remove focus from clicked step header if the step is not able to be selected - this._stepHeader.toArray()[index].nativeElement.blur(); - } else if (this._selectedIndex != index) { - this._emitStepperSelectionEvent(index); - this._focusIndex = this._selectedIndex; + if (this._steps) { + if (this._anyControlsInvalid(index) || index < this._selectedIndex && + !this._steps.toArray()[index].editable) { + // remove focus from clicked step header if the step is not able to be selected + this._stepHeader.toArray()[index].nativeElement.blur(); + } else if (this._selectedIndex != index) { + this._emitStepperSelectionEvent(index); + this._focusIndex = this._selectedIndex; + } + } else { + this._selectedIndex = this._focusIndex = index; } } private _selectedIndex: number = 0; @@ -280,9 +284,12 @@ export class CdkStepper { } private _anyControlsInvalid(index: number): boolean { - this._steps.toArray()[this._selectedIndex].interacted = true; + const steps = this._steps.toArray(); + + steps[this._selectedIndex].interacted = true; + if (this._linear && index >= 0) { - return this._steps.toArray().slice(0, index).some(step => step.stepControl.invalid); + return steps.slice(0, index).some(step => step.stepControl && step.stepControl.invalid); } return false; } diff --git a/src/lib/stepper/stepper.spec.ts b/src/lib/stepper/stepper.spec.ts index 7413e001946f..4d1dd1ce2b65 100644 --- a/src/lib/stepper/stepper.spec.ts +++ b/src/lib/stepper/stepper.spec.ts @@ -21,6 +21,7 @@ describe('MatHorizontalStepper', () => { imports: [MatStepperModule, NoopAnimationsModule, ReactiveFormsModule], declarations: [ SimpleMatHorizontalStepperApp, + SimplePreselectedMatHorizontalStepperApp, LinearMatHorizontalStepperApp ], providers: [ @@ -168,6 +169,18 @@ describe('MatHorizontalStepper', () => { it('should be able to move to next step even when invalid if current step is optional', () => { assertOptionalStepValidity(testComponent, fixture); }); + + it('should not throw when there is a pre-defined selectedIndex', () => { + fixture.destroy(); + + let preselectedFixture = TestBed.createComponent(SimplePreselectedMatHorizontalStepperApp); + let debugElement = preselectedFixture.debugElement; + + expect(() => preselectedFixture.detectChanges()).not.toThrow(); + + let stepHeaders = debugElement.queryAll(By.css('.mat-horizontal-stepper-header')); + assertSelectionChangeOnHeaderClick(preselectedFixture, stepHeaders); + }); }); }); @@ -874,3 +887,16 @@ class LinearMatVerticalStepperApp { }); } } + +@Component({ + template: ` + + + + + + ` +}) +class SimplePreselectedMatHorizontalStepperApp { + index = 0; +}