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`.
This commit is contained in:
Kristiyan Kostadinov
2018-03-01 01:05:39 +01:00
committed by tinayuangao
parent dd082cbdd6
commit 92ed9c8c63
6 changed files with 91 additions and 22 deletions
@@ -24,11 +24,22 @@ export interface Highlightable extends ListKeyManagerOption {
export class ActiveDescendantKeyManager<T> extends ListKeyManager<Highlightable & T> {
/**
* This method sets the active item to the item at the specified index.
* It also adds active styles to the newly active item and removes active
* styles from the previously active item.
* Sets the active item to the item at the specified index and adds the
* active styles to the newly active item. Also removes active styles
* from the previously active item.
* @param index Index of the item to be set as active.
*/
setActiveItem(index: number): void {
setActiveItem(index: number): void;
/**
* Sets the active item to the item to the specified one and adds the
* active styles to the it. Also removes active styles from the
* previously active item.
* @param item Item to be set as active.
*/
setActiveItem(item: T): void;
setActiveItem(index: any): void {
if (this.activeItem) {
this.activeItem.setInactiveStyles();
}
+13 -4
View File
@@ -32,11 +32,20 @@ export class FocusKeyManager<T> extends ListKeyManager<FocusableOption & T> {
}
/**
* This method sets the active item to the item at the specified index.
* It also adds focuses the newly active item.
* Sets the active item to the item at the specified
* index and focuses the newly active item.
* @param index Index of the item to be set as active.
*/
setActiveItem(index: number): void {
super.setActiveItem(index);
setActiveItem(index: number): void;
/**
* Sets the active item to the item that is specified and focuses it.
* @param item Item to be set as active.
*/
setActiveItem(item: T): void;
setActiveItem(item: any): void {
super.setActiveItem(item);
if (this.activeItem) {
this.activeItem.focus(this._origin);
@@ -349,6 +349,29 @@ describe('Key managers', () => {
.toBe(1, `Expected activeItemIndex to be updated when setActiveItem() was called.`);
});
it('should be able to set the active item by reference', () => {
expect(keyManager.activeItemIndex)
.toBe(0, `Expected first item of the list to be active.`);
keyManager.setActiveItem(itemList.items[2]);
expect(keyManager.activeItemIndex)
.toBe(2, `Expected activeItemIndex to be updated.`);
});
it('should be able to set the active item without emitting an event', () => {
const spy = jasmine.createSpy('change spy');
const subscription = keyManager.change.subscribe(spy);
expect(keyManager.activeItemIndex).toBe(0);
keyManager.updateActiveItem(2);
expect(keyManager.activeItemIndex).toBe(2);
expect(spy).not.toHaveBeenCalled();
subscription.unsubscribe();
});
it('should expose the active item correctly', () => {
keyManager.onKeydown(fakeKeyEvents.downArrow);
+35 -6
View File
@@ -162,14 +162,21 @@ export class ListKeyManager<T extends ListKeyManagerOption> {
* Sets the active item to the item at the index specified.
* @param index The index of the item to be set as active.
*/
setActiveItem(index: number): void {
setActiveItem(index: number): void;
/**
* Sets the active item to the specified item.
* @param item The item to be set as active.
*/
setActiveItem(item: T): void;
setActiveItem(item: any): void {
const previousIndex = this._activeItemIndex;
this._activeItemIndex = index;
this._activeItem = this._items.toArray()[index];
this.updateActiveItem(item);
if (this._activeItemIndex !== previousIndex) {
this.change.next(index);
this.change.next(this._activeItemIndex);
}
}
@@ -272,12 +279,34 @@ export class ListKeyManager<T extends ListKeyManagerOption> {
: this._setActiveItemByDelta(-1);
}
/**
* Allows setting the active without any other effects.
* @param index Index of the item to be set as active.
*/
updateActiveItem(index: number): void;
/**
* Allows setting the active item without any other effects.
* @param item Item to be set as active.
*/
updateActiveItem(item: T): void;
updateActiveItem(item: any): void {
const itemArray = this._items.toArray();
const index = typeof item === 'number' ? item : itemArray.indexOf(item);
this._activeItemIndex = index;
this._activeItem = itemArray[index];
}
/**
* Allows setting of the activeItemIndex without any other effects.
* @param index The new activeItemIndex.
* @deprecated Use `updateActiveItem` instead.
* @deletion-target 7.0.0
*/
updateActiveItemIndex(index: number) {
this._activeItemIndex = index;
updateActiveItemIndex(index: number): void {
this.updateActiveItem(index);
}
/**
+2 -5
View File
@@ -567,14 +567,11 @@ export class MatChipList extends _MatChipListMixinBase implements MatFormFieldCo
// Shift focus to the active item. Note that we shouldn't do this in multiple
// mode, because we don't know what chip the user interacted with last.
if (correspondingChip) {
const correspondingChipIndex = this.chips.toArray().indexOf(correspondingChip);
if (isUserInput) {
this._keyManager.setActiveItem(correspondingChipIndex);
this._keyManager.setActiveItem(correspondingChip);
} else {
this._keyManager.updateActiveItemIndex(correspondingChipIndex);
this._keyManager.updateActiveItem(correspondingChip);
}
}
}
}
+3 -3
View File
@@ -808,7 +808,7 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
// Shift focus to the active item. Note that we shouldn't do this in multiple
// mode, because we don't know what option the user interacted with last.
if (correspondingOption) {
this._keyManager.setActiveItem(this.options.toArray().indexOf(correspondingOption));
this._keyManager.setActiveItem(correspondingOption);
}
}
@@ -910,7 +910,7 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
this._selectionModel.toggle(option);
this.stateChanges.next();
wasSelected ? option.deselect() : option.select();
this._keyManager.setActiveItem(this._getOptionIndex(option)!);
this._keyManager.setActiveItem(option);
this._sortValues();
} else {
this._clearSelection(option.value == null ? undefined : option);
@@ -976,7 +976,7 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
if (this.empty) {
this._keyManager.setFirstItemActive();
} else {
this._keyManager.setActiveItem(this._getOptionIndex(this._selectionModel.selected[0])!);
this._keyManager.setActiveItem(this._selectionModel.selected[0]);
}
}
}