MenuActions based on data recieved from backend

I am trying to populate a sub menu in main menu bar at the top. The number of menu actions in the submenu will be dependent on the data that is received from the backend. Is it possible to dynamically load menu actions based on json data received from backend? If not, is there any other way?

I modified the example in this post to fit my use-case but it does not work: Menu contributions depending on the backend

Yes, it is possible. What did you try? Something like this should help:


    @inject(MenuModelRegistry)
    menuModel: MenuModelRegistry;

    @inject(CommandRegistry)
    commandRegistry: CommandRegistry;

    readonly toDisposeBeforeMenuUpdate = new DisposableCollection();

    onYouHaveReceivedSomethingFromTheBackend(data: object): void {
        this.toDisposeBeforeMenuUpdate.dispose();
        this.toDisposeBeforeMenuUpdate.push(this.commandRegistry.registerCommand({ id: 'some-id-from-the-data' }, { execute: () => { /* NOOP */ }}));
        this.menuModel.registerMenuAction(['some', 'path'], { commandId: 'some-id-from-the-data' });
        this.toDisposeBeforeMenuUpdate.push(Disposable.create(() => this.menuModel.unregisterMenuNode('some-id-from-the-data')));
    }

Thank you for the example. I am trying to implement this example in the front-end, inside MenuContribution, like this:

@injectable()
export class SerialMenuContribution implements MenuContribution {
@inject(CommandRegistry)
commands: CommandRegistry;

// Constructor creating instance of backend 
constructor(@inject(SerialService) protected readonly serialService: SerialService) { }

readonly disposeMenuUpdate = new DisposableCollection();

async registerMenus(menus: MenuModelRegistry): Promise<void> {
    const subMenuPath = [...MAIN_MENU_BAR, 'sample-menu'];

    menus.registerSubmenu(subMenuPath, 'Sample Menu', {
        order: '2' // that should put the menu right next to the File menu
    });

    // Data being fetched from the backend. Returns array of objects.
    const devices = await this.serialService.getUsbDevices()

    this.disposeMenuUpdate.dispose();
    devices.forEach((item: any) => {
        this.disposeMenuUpdate.push(this.commands.registerCommand(
            { id: item.path }, { execute: () => console.log("Hello" + item.path) }
        ));
        menus.registerMenuAction(subMenuPath, { commandId: item.path })
        this.disposeMenuUpdate.push(
            Disposable.create(() => menus.unregisterMenuNode(item.path))
        );
    })

Hi @usmnzain,
Is this working for you? I am trying to do the same, but i’m not getting it working. I see the menus being added to the MenuRegistry, but not visible in the menu itself.

  • If you are in electron, you have to recreate the menus manually. Always. Here is an example.
  • If you are running in browser env and want to insert into the top-level menus (such as File, Edit, Your_Item, Run, etc.), you have to do the same. Drop the menus and recreate them from scratch. (Get inspired from the electron-based example.)
  • However, if you are in a browser env and want to modify a non-top-level menu item and it does not work, it’s most likely a bug, and we need a bug report with an example to reproduce.

I hope this helps.

Thanks, this helps indeed. I am able to call the createMenuBar, but how can I call the setMenu in the browser env ?

Here is an example. You can try it in-action with the Remove 'Sample Menu' and Add 'Sample Menu' commands. It works only in the browser.

1 Like

Cool! Got it working now. Thx !