Skip to content

Commit 92ed9c8

Browse files
crisbetotinayuangao
authored andcommitted
feat(list-key-manager): accept item references in setActiveItem (#10029)
* Adds an overload to `setActiveItem` to allow for an item to be set as active, rather than its index. This avoids awkward conversions in certain cases (see the chips and select changes). * Deprecates the `updateActiveItemIndex` method in favor of `updateActiveItem` which accepts both an index and an item. * Fixes the active item not being updated when it is set via `updateActiveItemIndex`.
1 parent dd082cb commit 92ed9c8

File tree

6 files changed

+91
-22
lines changed

6 files changed

+91
-22
lines changed

src/cdk/a11y/key-manager/activedescendant-key-manager.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,22 @@ export interface Highlightable extends ListKeyManagerOption {
2424
export class ActiveDescendantKeyManager<T> extends ListKeyManager<Highlightable & T> {
2525

2626
/**
27-
* This method sets the active item to the item at the specified index.
28-
* It also adds active styles to the newly active item and removes active
29-
* styles from the previously active item.
27+
* Sets the active item to the item at the specified index and adds the
28+
* active styles to the newly active item. Also removes active styles
29+
* from the previously active item.
30+
* @param index Index of the item to be set as active.
3031
*/
31-
setActiveItem(index: number): void {
32+
setActiveItem(index: number): void;
33+
34+
/**
35+
* Sets the active item to the item to the specified one and adds the
36+
* active styles to the it. Also removes active styles from the
37+
* previously active item.
38+
* @param item Item to be set as active.
39+
*/
40+
setActiveItem(item: T): void;
41+
42+
setActiveItem(index: any): void {
3243
if (this.activeItem) {
3344
this.activeItem.setInactiveStyles();
3445
}

src/cdk/a11y/key-manager/focus-key-manager.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,20 @@ export class FocusKeyManager<T> extends ListKeyManager<FocusableOption & T> {
3232
}
3333

3434
/**
35-
* This method sets the active item to the item at the specified index.
36-
* It also adds focuses the newly active item.
35+
* Sets the active item to the item at the specified
36+
* index and focuses the newly active item.
37+
* @param index Index of the item to be set as active.
3738
*/
38-
setActiveItem(index: number): void {
39-
super.setActiveItem(index);
39+
setActiveItem(index: number): void;
40+
41+
/**
42+
* Sets the active item to the item that is specified and focuses it.
43+
* @param item Item to be set as active.
44+
*/
45+
setActiveItem(item: T): void;
46+
47+
setActiveItem(item: any): void {
48+
super.setActiveItem(item);
4049

4150
if (this.activeItem) {
4251
this.activeItem.focus(this._origin);

src/cdk/a11y/key-manager/list-key-manager.spec.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,29 @@ describe('Key managers', () => {
349349
.toBe(1, `Expected activeItemIndex to be updated when setActiveItem() was called.`);
350350
});
351351

352+
it('should be able to set the active item by reference', () => {
353+
expect(keyManager.activeItemIndex)
354+
.toBe(0, `Expected first item of the list to be active.`);
355+
356+
keyManager.setActiveItem(itemList.items[2]);
357+
expect(keyManager.activeItemIndex)
358+
.toBe(2, `Expected activeItemIndex to be updated.`);
359+
});
360+
361+
it('should be able to set the active item without emitting an event', () => {
362+
const spy = jasmine.createSpy('change spy');
363+
const subscription = keyManager.change.subscribe(spy);
364+
365+
expect(keyManager.activeItemIndex).toBe(0);
366+
367+
keyManager.updateActiveItem(2);
368+
369+
expect(keyManager.activeItemIndex).toBe(2);
370+
expect(spy).not.toHaveBeenCalled();
371+
372+
subscription.unsubscribe();
373+
});
374+
352375
it('should expose the active item correctly', () => {
353376
keyManager.onKeydown(fakeKeyEvents.downArrow);
354377

src/cdk/a11y/key-manager/list-key-manager.ts

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -162,14 +162,21 @@ export class ListKeyManager<T extends ListKeyManagerOption> {
162162
* Sets the active item to the item at the index specified.
163163
* @param index The index of the item to be set as active.
164164
*/
165-
setActiveItem(index: number): void {
165+
setActiveItem(index: number): void;
166+
167+
/**
168+
* Sets the active item to the specified item.
169+
* @param item The item to be set as active.
170+
*/
171+
setActiveItem(item: T): void;
172+
173+
setActiveItem(item: any): void {
166174
const previousIndex = this._activeItemIndex;
167175

168-
this._activeItemIndex = index;
169-
this._activeItem = this._items.toArray()[index];
176+
this.updateActiveItem(item);
170177

171178
if (this._activeItemIndex !== previousIndex) {
172-
this.change.next(index);
179+
this.change.next(this._activeItemIndex);
173180
}
174181
}
175182

@@ -272,12 +279,34 @@ export class ListKeyManager<T extends ListKeyManagerOption> {
272279
: this._setActiveItemByDelta(-1);
273280
}
274281

282+
/**
283+
* Allows setting the active without any other effects.
284+
* @param index Index of the item to be set as active.
285+
*/
286+
updateActiveItem(index: number): void;
287+
288+
/**
289+
* Allows setting the active item without any other effects.
290+
* @param item Item to be set as active.
291+
*/
292+
updateActiveItem(item: T): void;
293+
294+
updateActiveItem(item: any): void {
295+
const itemArray = this._items.toArray();
296+
const index = typeof item === 'number' ? item : itemArray.indexOf(item);
297+
298+
this._activeItemIndex = index;
299+
this._activeItem = itemArray[index];
300+
}
301+
275302
/**
276303
* Allows setting of the activeItemIndex without any other effects.
277304
* @param index The new activeItemIndex.
305+
* @deprecated Use `updateActiveItem` instead.
306+
* @deletion-target 7.0.0
278307
*/
279-
updateActiveItemIndex(index: number) {
280-
this._activeItemIndex = index;
308+
updateActiveItemIndex(index: number): void {
309+
this.updateActiveItem(index);
281310
}
282311

283312
/**

src/lib/chips/chip-list.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -567,14 +567,11 @@ export class MatChipList extends _MatChipListMixinBase implements MatFormFieldCo
567567
// Shift focus to the active item. Note that we shouldn't do this in multiple
568568
// mode, because we don't know what chip the user interacted with last.
569569
if (correspondingChip) {
570-
const correspondingChipIndex = this.chips.toArray().indexOf(correspondingChip);
571-
572570
if (isUserInput) {
573-
this._keyManager.setActiveItem(correspondingChipIndex);
571+
this._keyManager.setActiveItem(correspondingChip);
574572
} else {
575-
this._keyManager.updateActiveItemIndex(correspondingChipIndex);
573+
this._keyManager.updateActiveItem(correspondingChip);
576574
}
577-
578575
}
579576
}
580577
}

src/lib/select/select.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,7 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
808808
// Shift focus to the active item. Note that we shouldn't do this in multiple
809809
// mode, because we don't know what option the user interacted with last.
810810
if (correspondingOption) {
811-
this._keyManager.setActiveItem(this.options.toArray().indexOf(correspondingOption));
811+
this._keyManager.setActiveItem(correspondingOption);
812812
}
813813
}
814814

@@ -910,7 +910,7 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
910910
this._selectionModel.toggle(option);
911911
this.stateChanges.next();
912912
wasSelected ? option.deselect() : option.select();
913-
this._keyManager.setActiveItem(this._getOptionIndex(option)!);
913+
this._keyManager.setActiveItem(option);
914914
this._sortValues();
915915
} else {
916916
this._clearSelection(option.value == null ? undefined : option);
@@ -976,7 +976,7 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
976976
if (this.empty) {
977977
this._keyManager.setFirstItemActive();
978978
} else {
979-
this._keyManager.setActiveItem(this._getOptionIndex(this._selectionModel.selected[0])!);
979+
this._keyManager.setActiveItem(this._selectionModel.selected[0]);
980980
}
981981
}
982982
}

0 commit comments

Comments
 (0)