Skip to content

Commit e61c2fa

Browse files
authored
fix(cdk/a11y): activeItem out of date if active index is removed from ListKeyManager (#14471)
Fixes the `activeItem` on the `ListKeyManager` not matching the item at the `activeItemIndex`, if the `activeItem` is removed from the list. Fixes #14345.
1 parent 70120bd commit e61c2fa

File tree

4 files changed

+24
-4
lines changed

4 files changed

+24
-4
lines changed

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

+15-2
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,28 @@ describe('Key managers', () => {
8282
spyOn(keyManager, 'setActiveItem').and.callThrough();
8383
});
8484

85-
it('should maintain the active item if the amount of items changes', () => {
85+
it('should maintain the active item if the amount of items changes', fakeAsync(() => {
8686
expect(keyManager.activeItemIndex).toBe(0);
8787
expect(keyManager.activeItem!.getLabel()).toBe('one');
8888
itemList.reset([new FakeFocusable('zero'), ...itemList.toArray()]);
8989
itemList.notifyOnChanges();
90+
tick();
9091

9192
expect(keyManager.activeItemIndex).toBe(1);
9293
expect(keyManager.activeItem!.getLabel()).toBe('one');
93-
});
94+
}));
95+
96+
it('should keep the active item in sync if the active item is removed', fakeAsync(() => {
97+
expect(keyManager.activeItemIndex).toBe(0);
98+
expect(keyManager.activeItem!.getLabel()).toBe('one');
99+
100+
itemList.reset(itemList.toArray().slice(1));
101+
itemList.notifyOnChanges();
102+
tick();
103+
104+
expect(keyManager.activeItemIndex).toBe(0);
105+
expect(keyManager.activeItem!.getLabel()).toBe('two');
106+
}));
94107

95108
it('should start off the activeItem as null', () => {
96109
expect(new ListKeyManager([]).activeItem).toBeNull();

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

+5-2
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,11 @@ export class ListKeyManager<T extends ListKeyManagerOption> {
7070
const itemArray = newItems.toArray();
7171
const newIndex = itemArray.indexOf(this._activeItem);
7272

73-
if (newIndex > -1 && newIndex !== this._activeItemIndex) {
74-
this._activeItemIndex = newIndex;
73+
if (newIndex !== this._activeItemIndex) {
74+
// Timeout is required to avoid "changed after checked" errors.
75+
setTimeout(() => {
76+
this.updateActiveItem(newIndex > -1 ? newIndex : this._activeItemIndex);
77+
}, 0);
7578
}
7679
}
7780
});

src/material-experimental/mdc-menu/menu.spec.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1176,6 +1176,7 @@ describe('MDC-based MatMenu', () => {
11761176
fixture.detectChanges();
11771177
tick(500);
11781178
fixture.detectChanges();
1179+
tick();
11791180

11801181
expect(fixture.componentInstance.items.length).toBe(0);
11811182
}));
@@ -1201,6 +1202,7 @@ describe('MDC-based MatMenu', () => {
12011202
.toBe(true);
12021203
tick(500);
12031204
fixture.detectChanges();
1205+
tick();
12041206

12051207
expect(trigger.menuOpen).withContext('Expected menu to be closed').toBe(false);
12061208
}));

src/material/menu/menu.spec.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1171,6 +1171,7 @@ describe('MatMenu', () => {
11711171
fixture.detectChanges();
11721172
tick(500);
11731173
fixture.detectChanges();
1174+
tick();
11741175

11751176
expect(fixture.componentInstance.items.length).toBe(0);
11761177
}));
@@ -1196,6 +1197,7 @@ describe('MatMenu', () => {
11961197
.toBe(true);
11971198
tick(500);
11981199
fixture.detectChanges();
1200+
tick();
11991201

12001202
expect(trigger.menuOpen).withContext('Expected menu to be closed').toBe(false);
12011203
}));

0 commit comments

Comments
 (0)