Skip to content

Commit 5564d7d

Browse files
feat(cdk/menu): add setActiveMenuItem to cdkMenu (#31371)
closes #31370+
1 parent 663d816 commit 5564d7d

File tree

3 files changed

+55
-0
lines changed

3 files changed

+55
-0
lines changed

goldens/cdk/menu/index.api.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ export abstract class CdkMenuBase extends CdkMenuGroup implements Menu, AfterCon
107107
protected ngZone: NgZone;
108108
orientation: 'horizontal' | 'vertical';
109109
protected pointerTracker?: PointerFocusTracker<CdkMenuItem>;
110+
setActiveMenuItem(item: number | CdkMenuItem): void;
110111
protected triggerItem?: CdkMenuItem;
111112
// (undocumented)
112113
static ɵdir: i0.ɵɵDirectiveDeclaration<CdkMenuBase, never, never, { "id": { "alias": "id"; "required": false; }; }, {}, ["items"], never, true, never>;

src/cdk/menu/menu-base.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,20 @@ export abstract class CdkMenuBase
141141
this.keyManager.setLastItemActive();
142142
}
143143

144+
/**
145+
* Sets the active item to the item at the specified index and focuses the newly active item.
146+
* @param item The index of the item to be set as active, or the CdkMenuItem instance.
147+
*/
148+
setActiveMenuItem(item: number | CdkMenuItem) {
149+
if (this.keyManager) {
150+
if (typeof item === 'number') {
151+
this.keyManager.setActiveItem(item);
152+
} else {
153+
this.keyManager.setActiveItem(item);
154+
}
155+
}
156+
}
157+
144158
/** Gets the tabindex for this menu. */
145159
_getTabIndex() {
146160
return this._tabIndexSignal();

src/cdk/menu/menu.spec.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,31 @@ describe('Menu', () => {
502502
}));
503503
});
504504
});
505+
506+
describe('menu with active item', () => {
507+
let fixture: ComponentFixture<MenuWithActiveItem>;
508+
let nativeMenuItems: HTMLElement[];
509+
510+
beforeEach(waitForAsync(() => {
511+
TestBed.configureTestingModule({
512+
imports: [CdkMenuModule, MenuWithActiveItem],
513+
});
514+
}));
515+
516+
beforeEach(() => {
517+
fixture = TestBed.createComponent(MenuWithActiveItem);
518+
fixture.detectChanges();
519+
520+
nativeMenuItems = fixture.debugElement
521+
.queryAll(By.directive(CdkMenuItem))
522+
.map(e => e.nativeElement);
523+
});
524+
525+
it('should set the active item with setActiveMenuItem', () => {
526+
fixture.componentInstance.menu.setActiveMenuItem(2);
527+
expect(document.activeElement).toEqual(nativeMenuItems[2]);
528+
});
529+
});
505530
});
506531

507532
@Component({
@@ -655,3 +680,18 @@ class WithComplexNestedMenusOnBottom {
655680

656681
@ViewChildren(CdkMenu) menus: QueryList<CdkMenu>;
657682
}
683+
684+
@Component({
685+
template: `
686+
<div cdkMenu>
687+
<button cdkMenuItem>Inbox</button>
688+
<button cdkMenuItem>Starred</button>
689+
<button cdkMenuItem>Foo</button>
690+
<button cdkMenuItem>Bar</button>
691+
</div>
692+
`,
693+
imports: [CdkMenuModule],
694+
})
695+
class MenuWithActiveItem {
696+
@ViewChild(CdkMenu) menu: CdkMenu;
697+
}

0 commit comments

Comments
 (0)