Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions goldens/cdk/menu/index.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ export abstract class CdkMenuBase extends CdkMenuGroup implements Menu, AfterCon
protected ngZone: NgZone;
orientation: 'horizontal' | 'vertical';
protected pointerTracker?: PointerFocusTracker<CdkMenuItem>;
setActiveMenuItem(item: number | CdkMenuItem): void;
protected triggerItem?: CdkMenuItem;
// (undocumented)
static ɵdir: i0.ɵɵDirectiveDeclaration<CdkMenuBase, never, never, { "id": { "alias": "id"; "required": false; }; }, {}, ["items"], never, true, never>;
Expand Down
14 changes: 14 additions & 0 deletions src/cdk/menu/menu-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,20 @@ export abstract class CdkMenuBase
this.keyManager.setLastItemActive();
}

/**
* Sets the active item to the item at the specified index and focuses the newly active item.
* @param item The index of the item to be set as active, or the CdkMenuItem instance.
*/
setActiveMenuItem(item: number | CdkMenuItem) {
if (this.keyManager) {
if (typeof item === 'number') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need this check, the key manager does it automatically.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes its not needed but typescript is not happy so I had to add.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Let's keep it as is and I'll clean it up later.

this.keyManager.setActiveItem(item);
} else {
this.keyManager.setActiveItem(item);
}
}
}

/** Gets the tabindex for this menu. */
_getTabIndex() {
return this._tabIndexSignal();
Expand Down
40 changes: 40 additions & 0 deletions src/cdk/menu/menu.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,31 @@ describe('Menu', () => {
}));
});
});

describe('menu with active item', () => {
let fixture: ComponentFixture<MenuWithActiveItem>;
let nativeMenuItems: HTMLElement[];

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [CdkMenuModule, MenuWithActiveItem],
});
}));

beforeEach(() => {
fixture = TestBed.createComponent(MenuWithActiveItem);
fixture.detectChanges();

nativeMenuItems = fixture.debugElement
.queryAll(By.directive(CdkMenuItem))
.map(e => e.nativeElement);
});

it('should set the active item with setActiveMenuItem', () => {
fixture.componentInstance.menu.setActiveMenuItem(2);
expect(document.activeElement).toEqual(nativeMenuItems[2]);
});
});
});

@Component({
Expand Down Expand Up @@ -655,3 +680,18 @@ class WithComplexNestedMenusOnBottom {

@ViewChildren(CdkMenu) menus: QueryList<CdkMenu>;
}

@Component({
template: `
<div cdkMenu>
<button cdkMenuItem>Inbox</button>
<button cdkMenuItem>Starred</button>
<button cdkMenuItem>Foo</button>
<button cdkMenuItem>Bar</button>
</div>
`,
imports: [CdkMenuModule],
})
class MenuWithActiveItem {
@ViewChild(CdkMenu) menu: CdkMenu;
}