Skip to content

Commit

Permalink
fix(material/stepper): two-way binding for selectedIndex (#27232)
Browse files Browse the repository at this point in the history
* fix(material/stepper): two-way binding for selectedIndex

adds two-way binding for selectedIndex, previously stepper had selectionChange which include selectedIndex & other properties in it

fixes #15627

* fixup! fix(material/stepper): two-way binding for selectedIndex
  • Loading branch information
naaajii authored Jun 6, 2023
1 parent 6f79a99 commit 1cb210b
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 1 deletion.
4 changes: 4 additions & 0 deletions src/cdk/stepper/stepper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,9 @@ export class CdkStepper implements AfterContentInit, AfterViewInit, OnDestroy {
/** Event emitted when the selected step has changed. */
@Output() readonly selectionChange = new EventEmitter<StepperSelectionEvent>();

/** Output to support two-way binding on `[(selectedIndex)]` */
@Output() readonly selectedIndexChange: EventEmitter<number> = new EventEmitter<number>();

/** Used to track unique ID for each stepper component. */
_groupId: number;

Expand Down Expand Up @@ -526,6 +529,7 @@ export class CdkStepper implements AfterContentInit, AfterViewInit, OnDestroy {
: this._keyManager.updateActiveItem(newIndex);

this._selectedIndex = newIndex;
this.selectedIndexChange.emit(this._selectedIndex);
this._stateChanged();
}

Expand Down
42 changes: 42 additions & 0 deletions src/material/stepper/stepper.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1571,6 +1571,35 @@ describe('MatStepper', () => {
expect(element.textContent).toContain('Step 3 content');
});
});

describe('stepper with two-way binding on selectedIndex', () => {
it('should update selectedIndex in component on navigation', () => {
const fixture = createComponent(StepperWithTwoWayBindingOnSelectedIndex);
fixture.detectChanges();

expect(fixture.componentInstance.index).toBe(0);

const stepHeaders = fixture.debugElement.queryAll(By.css('.mat-horizontal-stepper-header'));

let lastStepHeaderEl = stepHeaders[2].nativeElement;
lastStepHeaderEl.click();
fixture.detectChanges();

expect(fixture.componentInstance.index).toBe(2);

let middleStepHeaderEl = stepHeaders[1].nativeElement;
middleStepHeaderEl.click();
fixture.detectChanges();

expect(fixture.componentInstance.index).toBe(1);

let firstStepHeaderEl = stepHeaders[0].nativeElement;
firstStepHeaderEl.click();
fixture.detectChanges();

expect(fixture.componentInstance.index).toBe(0);
});
});
});

/** Asserts that keyboard interaction works correctly. */
Expand Down Expand Up @@ -2166,3 +2195,16 @@ class StepperWithLazyContent {
class HorizontalStepperWithDelayedStep {
renderSecondStep = false;
}

@Component({
template: `
<mat-stepper [(selectedIndex)]="index">
<mat-step label="One"></mat-step>
<mat-step label="Two"></mat-step>
<mat-step label="Three"></mat-step>
</mat-stepper>
`,
})
class StepperWithTwoWayBindingOnSelectedIndex {
index: number = 0;
}
3 changes: 2 additions & 1 deletion tools/public_api_guard/cdk/stepper.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,14 @@ export class CdkStepper implements AfterContentInit, AfterViewInit, OnDestroy {
set selected(step: CdkStep | undefined);
get selectedIndex(): number;
set selectedIndex(index: NumberInput);
readonly selectedIndexChange: EventEmitter<number>;
readonly selectionChange: EventEmitter<StepperSelectionEvent>;
_stateChanged(): void;
_stepHeader: QueryList<CdkStepHeader>;
readonly steps: QueryList<CdkStep>;
_steps: QueryList<CdkStep>;
// (undocumented)
static ɵdir: i0.ɵɵDirectiveDeclaration<CdkStepper, "[cdkStepper]", ["cdkStepper"], { "linear": { "alias": "linear"; "required": false; }; "selectedIndex": { "alias": "selectedIndex"; "required": false; }; "selected": { "alias": "selected"; "required": false; }; "orientation": { "alias": "orientation"; "required": false; }; }, { "selectionChange": "selectionChange"; }, ["_steps", "_stepHeader"], never, false, never, false>;
static ɵdir: i0.ɵɵDirectiveDeclaration<CdkStepper, "[cdkStepper]", ["cdkStepper"], { "linear": { "alias": "linear"; "required": false; }; "selectedIndex": { "alias": "selectedIndex"; "required": false; }; "selected": { "alias": "selected"; "required": false; }; "orientation": { "alias": "orientation"; "required": false; }; }, { "selectionChange": "selectionChange"; "selectedIndexChange": "selectedIndexChange"; }, ["_steps", "_stepHeader"], never, false, never, false>;
// (undocumented)
static ɵfac: i0.ɵɵFactoryDeclaration<CdkStepper, [{ optional: true; }, null, null]>;
}
Expand Down

0 comments on commit 1cb210b

Please sign in to comment.