I would like to add a quit submenu item under the File menu item in my Electron JS app, but only on Windows and Linux. On Mac, I already have set up a Quit submenu item under the app name menu item. Currently, this is my code:
function createMenu(){
const isMac = process.platform === 'darwin';
const menu = [
{
label: "File",
submenu: [
{
label: 'Add expense',
},
!isMac && {
label: 'Quit',
click(){
app.quit()
},
accelerator: 'Ctrl+Q'
}
]
},
{
label: "Menu2",
submenu: [{label: 'Ok'}]
}
];
// Mac First Item in Template refers to app name (won't be able to override unless you package application)
isMac && menu.unshift({
label: app.name,
submenu: [
{
label: 'About',
click(){
open('https://www.google.com') // Using the open package
}
},
{
label: 'Quit',
click(){
app.quit()
},
accelerator: 'Cmd+Q'
}
]
})
return menu;
}
When I run this, however, I get an error saying
TypeError: Invalid template for MenuItem: must have at least one of label, role or type
How should I go about doing this?
Thank you!
You're getting the error because of the way you're trying to conditionally insert an object into the list literal.
// The not macOS case:
> [ {"foo": 15}, true && {"bar": 123} ]
[ { foo: 15 }, { bar: 123 } ]
// The macOS case:
> [ {"foo": 15}, false && {"bar": 123} ]
[ { foo: 15 }, false ]
In the latter case, you end up inserting a false
element into the array, which is why you get the error.
If you want to use such a shorthand, you can use:
> [ {"foo": 15}, ...(true?[{"bar": 123}]:[]) ]
[ { foo: 15 }, { bar: 123 } ]
> [ {"foo": 15}, ...(false?[{"bar": 123}]:[]) ]
[ { foo: 15 } ]
In your use case, this would get you:
const menu = [
{
label: "File",
submenu: [
{
label: 'Add expense',
},
...(!isMac)?[{
label: 'Quit',
click(){
app.quit()
},
accelerator: 'Ctrl+Q'
}]:[]
]
},
{
label: "Menu2",
submenu: [{label: 'Ok'}]
}
];
Alternatively, you can simply adjust the menu template:
const menu = [
{
label: "File",
submenu: [
{
label: 'Add expense',
}
]
},
{
label: "Menu2",
submenu: [{label: 'Ok'}]
}
];
if (!isMac) {
menu[0]["submenu"].push({
label: 'Quit',
click(){
app.quit()
},
accelerator: 'Ctrl+Q'
})
}
Which one to use is up to you; in the second case you may need to update the menu addressing if the structure changes. You should also weigh readability.