WebExeBuilder Documentation

onAppMenuItemClick

Category: Events

Namespace: web.events.onAppMenuItemClick

Description

Fires when the user clicks any item in the native application menu bar created via web.appMenu.createMenu. The callback receives the integer id of the clicked menu item.

Critical: This handler must be set in the Builder's "BEFORE DOM Exists JS" slot (the JavaScript / NavigationStarting field), NOT inside the HTML page's <script> tag. The Delphi bridge callback wiring happens during NavigationStarting — setting the handler in page JS silently fails.

Syntax

web.events.onAppMenuItemClick = async function(menuId) {
    // menuId is the integer id assigned in web.appMenu.createMenu()
};

Parameters

The callback receives one argument:

  • menuId number — The integer id of the menu item that was clicked, matching the id used when building the menu structure

Returns

Nothing. This is an event handler assignment, not a function call.

Examples

Basic usage

// Goes in Builder's "BEFORE DOM Exists JS" slot
web.events.onAppMenuItemClick = function(menuId) {
    console.log('Menu item clicked:', menuId);
};

Full menu setup with handler

// Goes in Builder's "BEFORE DOM Exists JS" slot

web.events.onAppMenuItemClick = async function(menuId) {
    switch (menuId) {
        case 1: // File > New
            newDocument();
            break;
        case 2: // File > Open
            const file = await web.dialogs.openFile();
            if (file) openDocument(file);
            break;
        case 3: // File > Save
            await saveDocument();
            break;
        case 9: // File > Exit
            await web.app.close();
            break;
        case 10: // Help > About
            await web.app.showAbout();
            break;
    }
};

if (!window.menuCreated) {
    window.menuCreated = true;
    web.appMenu.createMenu({
        items: JSON.stringify([
            {
                id: 100, caption: 'File',
                items: [
                    { id: 1, caption: 'New' },
                    { id: 2, caption: 'Open...' },
                    { id: 3, caption: 'Save' },
                    { separator: true },
                    { id: 9, caption: 'Exit' }
                ]
            },
            {
                id: 200, caption: 'Help',
                items: [
                    { id: 10, caption: 'About' }
                ]
            }
        ])
    });
}

Enable/disable items based on state

// Goes in Builder's "BEFORE DOM Exists JS" slot

web.events.onAppMenuItemClick = async function(menuId) {
    if (menuId === 2) { // Save
        await saveCurrentFile();
    } else if (menuId === 3) { // Close
        currentFile = null;
        // Disable save after close
        await web.appMenu.updateMenu({
            items: JSON.stringify([{ id: 2, enabled: false }])
        });
    }
};

Placement Rule

Where Works?
Builder "BEFORE DOM Exists JS" slot ✅ Yes — correct
Inside HTML <script> tag ❌ No — silently fails
Inside DOMContentLoaded listener ❌ No — silently fails

Always register onAppMenuItemClick before calling createMenu, and both must be in the NavigationStarting JS slot.

Use Cases

  • Handle File > New, Open, Save, Exit actions
  • Toggle fullscreen, zoom, or other view settings
  • Open Help/About dialogs
  • Enable or disable menu items in response to app state changes

Notes

  • Menu item id values must be integers — string IDs throw "'x' is not a valid integer value"
  • Register the handler before calling web.appMenu.createMenu() — not after
  • Use window.menuCreated guard to prevent double-creation on page reloads
  • Only one handler can be assigned at a time — reassigning replaces the previous handler
  • Top-level parent items (e.g. "File", "Help") do not fire the callback when clicked — only leaf items do
  • See web.appMenu.createMenu for building the menu structure
  • See web.appMenu.updateMenu for changing item state (enabled/visible/caption) after creation