What Will I Learn?
In this tutorial we gonna continue the main menu template after the overwrite the default template that we did before. and We will added that this feature to Mac OS and I will explain What should we use to apply this. then I will explain how to create interactive functions to achieve the purpose of the application.
- Main Menu Template Support for Mac OS
- Add Developer Tools
- Add functionality by Using Vanilla JavaScript
- Prepare add item functionality insinde
addWindow.html
&index.js
Requirements
- Any Modern OS (Windows - Mac - Linux)
- Text Editor (VSCode eg.)
- Node.js (8.9.4) or above
Difficulty
- Intermediate
Menu Template Support for Mac OS
if you started the app from mac you properly seeing electron by default not file. and basically to fix that we gonna push an empty object to mainMenuBar
Array.
The following an example for the empty object:
const mainMenuBar = [
{}, //an empty object
{
label: 'File',
submenu:[
{
label:'Add Item',
click(){
createAddWindow();
}
},
{
label:'Clear Items',
click(){
mainWindow.webContents.send('item:clear');
}
},
{
label: 'Quit',
accelerator:process.platform == 'darwin' ? 'Command+Q' : 'Ctrl+Q',
click(){
app.quit();
}
}
]
}
];
An issue will appear you will got a little space before file label that on other platforms like windows.
To fix that issue we gonna check to see if we are on a mac.
so if we are on a mac its gonna push an empty object in that case as we haved used before process.platform
to define Mac OS as darwin
if(process.platform == 'darwin'){
mainMenuBar.unshift({});
}
Add Developer Tools
If you're not in a production mode you probably need a developer tools as well as the ability to reload the application that we have created or even edited.
So I will create if statement to check if we are not on production mode
if(process.env.NODE_ENV !== 'production'){
}
Then I gonna push to mainMenuBar
Array the developer tools label as well as submenu
First I will create the developer tools label like the following in object:
if(process.env.NODE_ENV !== 'production'){
mainMenuBar.push({
label: 'Developer Tools'
});
}
Then I will add a submenu that has Toggle DevTools
ability
if(process.env.NODE_ENV !== 'production'){
mainMenuBar.push({
label: 'Developer Tools',
submenu:[
{
label: 'Toggle DevTools',
]
});
}
Then I gonna use click function that we need to pass in item, focusedWindow
then we need to make dev tools to popup on that on in our main window to show up.
and that by using focusedWindow.toggleDevTools();
Then I will add an accelerator for a hot key as Command + I
on Mac OS and for Window, Linux we gonna use CTRL + I
and then we gonna add a reload option and we gonna put all that inside submenu array as objects and we gonna use the comma as well.
if(process.env.NODE_ENV !== 'production'){
mainMenuBar.push({
label: 'Developer Tools',
submenu:[
{
role: 'reload'
},
{
label: 'Toggle DevTools',
accelerator:process.platform == 'darwin' ? 'Command+I' : 'Ctrl+I',
click(item, focusedWindow){
focusedWindow.toggleDevTools();
}
}
]
});
}
Let's test it by using npm start
in terminal or command prompt.
It Works!
Add functionality by Using Vanilla JavaScript
Now we are ready to start the functionality of adding an item to the list so we gonna start off with the add window HTML that's where we are going to working on for a little bit.
Also we are gonna use some vanilla JavaScript to catch the item when some one puts in some text.
then we gonna use something called IPC
renderer which is going to be used to basically send an event with a payload from our HTML
file to the index.js
We gonna send that item here then we gonna take that item and send it to the main window.
so we can list it on the main window.
First Open addWindow.html
then create script
tags
then add variable electron that will require electron
also create a variable called {ipcRenderer}
and set that to electron
.
The following is an example:
<script>
const electron = require('electron');
const {ipcRenderer} = electron;
</script>
Then we will need to catch that item. so we gonna use some Vanilla JavaScript
we are actually gonna using quit a bit from DOM. by using the document
then querySelector
as method to catch item
<script>
const electron = require('electron');
const {ipcRenderer} = electron;
const form = document.querySelector('item`);
</script>
Then we gonna listen for a submit event and then we will create a submitForm function for that parameter inside AddEventListener
and that's gonna get passed in an event parameter
<script>
const electron = require('electron');
const {ipcRenderer} = electron;
const form = document.querySelector('form');
form.addEventListener('submit', submitForm);
function submitForm(e){
}
</script>
Now we you try to submit a form its gonna automatically just try to submit to a file as it would normally so we need to stop that from happening so we need to take that event parameter our event object and call prevent default. Then create a console.log
for a test.
The following is an example:
<script>
const electron = require('electron');
const {ipcRenderer} = electron;
const form = document.querySelector('form');
form.addEventListener('submit', submitForm);
function submitForm(e){
e.preventDefault();
console.log('Works');
}
</script>
Now Let's test it by using npm start
from terminal or command prompt.
Now we will need to catch the text inside input that has an ID of item
and we gonna set that value or text inside a new variable called item
.
and then by using ipcRenderer
we gonna use send
method to send it after the catch of the item. it works like socket.io if you've an experience with that if you're sending it from the client to the sever you are just kind of giving it a name and then you are sending the data along with it then we gonna catch on the index.js
side
<script>
const electron = require('electron');
const {ipcRenderer} = electron;
const form = document.querySelector('form');
form.addEventListener('submit', submitForm);
function submitForm(e){
e.preventDefault();
const item = document.querySelector('#item').value;
ipcRenderer.send('item:add', item);
}
</script>
Now save it. then go to the index.js
file
and to catch this we need to bring something called IPC main
so up inside the file as we gonna doing our destructing and we gonna add in ipcMain
that inside the variable of objects that we have already created before.
The Following is an example:
const {
app,
BrowserWindow,
Menu,
ipcMain
} = electron;
Then go under create AddWindow
that we have created for garbage collection handle.
right above the mainMenuBar
.
so just Create an ipcMain.on()
then add the item whatever we gave that name which is item add so on that happens we gonna call a function and that function gonna passed in an event and the item. whatever we sent and what we want to do is send it to the main window coming from the add window. then close addWindow
The Following is an example:
ipcMain.on('item:add', function(e, item){
mainWindow.webContents.send('item:add', item);
addWindow.close();
});
and to make sure its coming from addWindow to mainWindow we gonna use a console.log()
as we did before.
ipcMain.on('item:add', function(e, item){
console.log(item);
mainWindow.webContents.send('item:add', item);
addWindow.close();
});
Now Let's test it by using npm start
from terminal or command prompt.
Now we have finished that part of our series.
Here is the final result for index.js
const electron = require('electron');
const url = require('url');
const path = require('path');
const {app, BrowserWindow, Menu, ipcMain} = electron;
let mainWindow;
let addWindow;
app.on('ready', function () {
mainWindow = new BrowserWindow({});
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, 'mainWindow.html'),
protocol: 'file:',
slashes: true
}));
const mainMenu = Menu.buildFromTemplate(mainMenuBar);
Menu.setApplicationMenu(mainMenu);
mainWindow.on('closed', function () {
app.quit();
});
});
ipcMain.on('item:add', function(e, item){
console.log(item);
mainWindow.webContents.send('item:add', item);
addWindow.close();
});
// Create menu template
const mainMenuBar = [
// Each object is a dropdown
{
label: 'File',
submenu:[
{
label:'Add Item',
click(){
createAddWindow();
}
},
{
label:'Clear Items',
click(){
mainWindow.webContents.send('item:clear');
}
},
{
label: 'Quit',
accelerator:process.platform == 'darwin' ? 'Command+Q' : 'Ctrl+Q',
click(){
app.quit();
}
}
]
}
];
function createAddWindow() {
addWindow = new BrowserWindow({
width: 300,
height: 200,
title: 'Add Shopping List Item'
});
addWindow.loadURL(url.format({
pathname: path.join(__dirname, 'addWindow.html'),
protocol: 'file:',
slashes: true
}));
addWindow.on('close', function () {
addWindow = null;
});
}
// If OSX, add empty object to menu
if(process.platform == 'darwin'){
mainMenuBar.unshift({});
}
// Add developer tools option if in dev
if(process.env.NODE_ENV !== 'production'){
mainMenuBar.push({
label: 'Developer Tools',
submenu:[
{
role: 'reload'
},
{
label: 'Toggle DevTools',
accelerator:process.platform == 'darwin' ? 'Command+I' : 'Ctrl+I',
click(item, focusedWindow){
focusedWindow.toggleDevTools();
}
}
]
});
}
and for addWindow.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Add Shopping Item</title>
</head>
<body>
<div class="container">
<form>
<div>
<label>Enter Item</label>
<input type="text" id="item" autofocus>
</div>
<button class="waves-effect waves-light btn" type="submit">Add Item</button>
</form>
</div>
<script>
const electron = require('electron');
const {ipcRenderer} = electron;
const form = document.querySelector('form');
form.addEventListener('submit', submitForm);
function submitForm(e){
e.preventDefault();
const item = document.querySelector('#item').value;
ipcRenderer.send('item:add', item);
}
</script>
</body>
</html>
What's Next?
We will continue the functionality of add an item then we will create a functionality to clear items then in other parts we will create a modern look for our application by using some HTML/CSS frameworks.
Previous Tutorials
- Build a Shopping List App with Electron #1: Getting Started
- Build a Shopping List App with Electron #2: Create Menu Template
All Images/GIF has been created by @jinzo for an open source project.
Posted on Utopian.io - Rewarding Open Source Contributors
Thank you for the contribution. It has been approved.
You can contact us on Discord.
[utopian-moderator]
Another awesome tutorial
Very Informative.
Thanks.
Hey @jinzo I am @utopian-io. I have just upvoted you!
Achievements
Suggestions
Get Noticed!
Community-Driven Witness!
I am the first and only Steem Community-Driven Witness. Participate on Discord. Lets GROW TOGETHER!
Up-vote this comment to grow my power and help Open Source contributions like this one. Want to chat? Join me on Discord https://discord.gg/Pc8HG9x