Each time the window starts to loads new html or makes a makes request to the server the Window will go white until the page has finished loading or server has responded to the request. This does not look good at all and can be quite jarring.
How can I stop this?
The code if you wish to see it app.js
const {app, BrowserWindow} = require('electron');
const path = require('path');
const url = require('url');
let win;
function createWindow () {
// Create the browser window.
win = new BrowserWindow({width: 800, height: 600});
win.loadURL(url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}));
win.on('closed', () => {
win = null;
})
}
app.on('ready', createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (win === null) {
createWindow()
}
});
inedx.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body style="background-color: #222222">
Click on me to see a flash
</body>
</html>
As far as I have seen (like here: 4 must-know tips for building cross platform Electron apps) setting the background color of the window is the typical way to at least mitigate the "flash". Perhaps you could get fancy with a CSS transition to fade out the window content before loading and then fade it in once the new content has loaded?
From that site:
2.1 Specify a BrowserWindow background color If your application has a non-white background color, make sure to specify it in your
BrowserWindow options. This won't prevent the square-of-solid-color
while your application loads, but at least it doesn't also change
color halfway through:
mainWindow = new BrowserWindow({
title: 'ElectronApp',
backgroundColor: '#002b36',
};
2.2 Hide your application until your page has loaded: Because we're actually in the browser, we can choose to hide the windows until we
know all our resources have been loaded in. Upon starting, make sure
to hide your browser window:
var mainWindow = new BrowserWindow({
title: 'ElectronApp',
show: false,
};
Then, when everything is loaded, show the window and focus it so it
pops up for the user. You can do this with the "ready-to-show" event
on your BrowserWindow, which is recommended, or the
'did-finish-load' event on your webContents.
mainWindow.on('ready-to-show', function() {
mainWindow.show();
mainWindow.focus();
});
Related
I am trying to create a Debug app for Body Positioning Data. This data is received as JSON via MQTT in my receiveAndConversion.js. I was able to receive the data properly and print to console. So far so good. But now I want in my main window the values that I receive to show up (make the screen green for example when hand closed).
I have tried a lot of things including ipc and adding
nodeIntegration: true, contextIsolation: false, enableRemoteModule: true, as preferences in main.js
Researching this is kind of a pain, as I always get to questions where the person tries to change the DOM from main.js instead of the renderer.
I am new to electron and have been spending hours on the documentation but all their examples are either triggerd on launch of the app or by a button (user interaction). I need to change the DOM when a new message is received, independent on user interaction or other things.
My structure at the moment is like this:
main.js
receiveAndConversion.js
index.html
renderer.js
Except for receiveAndConversion.js, renderer.js and the mentioned Preferences in main.js, the code is more or less the same as The quick start guide.
The main issue that seems to block me is, that I cant seem to be able to call my renderer.js from my receiveAndConversion.js mqttClient.on() which runs when I have received a new message. My thinking was I could just call from there a render function in render.js but as it is called from receiveAndConversion.js I get a "document is not defined" error (at least I believe that's the reason).
I would really appreciate if you had an idea for me on how to implement this without having to put everything in main.js.
You can find the complete code below.
// main.js
// Modules to control application life and create native browser window
const { app, BrowserWindow, ipcMain } = require('electron')
//const Renderer = require('electron/renderer')
const path = require('path')
const mqttClient = require('./receiveAndConversion.js')
const createWindow = () => {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
//nativeWindowOpen: true,
nodeIntegration: true,
contextIsolation: false,
enableRemoteModule: true,
preload: path.join(__dirname, 'preload.js')
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
//
//ipcMain.handle('left-hand-closed', (event, arg) => {
// console.log('left hand is closed');
//}
//)
createWindow()
app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
<!--index.html-->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
We are using Node.js <span id="node-version"></span>,
Chromium <span id="chrome-version"></span>,
and Electron <span id="electron-version"></span>.
<!-- Create different field which will be used to visualise if hands are open or not. So one field for left hand one field for right hand. -->
<div id="left-hand"></div>
<div id="right-hand"></div>
<!-- You can also require other files to run in this process -->
<script src="./renderer.js"></script>
</body>
</html>
//renderer.js
// get info of open or closed hands from receiveAndConversion.js
// then make the left-hand div or right-hand div green or red depending on open or closed
//const {ipcRenderer} = require('electron')
// //write something in the divs
// leftHandDiv.innerHTML = 'Left Hand: ' + leftHandClosed
// rightHandDiv.innerHTML = 'Right Hand: ' + rightHandClosed
// ipcRenderer.handle('left-hand-closed', (event, arg) => {
// leftHandDiv.innerHTML = 'Left Hand: ' + arg
// }
// )
// ipcRenderer.handle('right-hand-closed', (event, arg) => {
// rightHandDiv.innerHTML = 'Right Hand: ' + arg
// }
// )
function handChange(leftHandClosed, rightHandClosed) {
//get the divs from the html file
const leftHandDiv = document.getElementById('left-hand')
const rightHandDiv = document.getElementById('right-hand')
//check if the hand is open or closed
if (leftHandClosed) {
leftHandDiv.style.backgroundColor = 'green'
console.log('left hand is closed');
} else {
leftHandDiv.style.backgroundColor = 'red'
console.log('left hand is open');
}
if (rightHandClosed) {
rightHandDiv.style.backgroundColor = 'green'
console.log('right hand is closed');
} else {
rightHandDiv.style.backgroundColor = 'red'
console.log('right hand is open');
}
}
//make handChange() usable outside of the renderer.js
module.exports = {
handChange
}
// preload.js
// All of the Node.js APIs are available in the preload process.
// It has the same sandbox as a Chrome extension.
window.addEventListener('DOMContentLoaded', () => {
const replaceText = (selector, text) => {
const element = document.getElementById(selector)
if (element) element.innerText = text
}
for (const dependency of ['chrome', 'node', 'electron']) {
replaceText(`${dependency}-version`, process.versions[dependency])
}
})
To keep your receiveAndConversion.js file separate from your main.js file and send signals via IPC to index.html, you need access to Electrons window instance of index.html. This can be achieved by using a "getter" method. Separating the creation (and getting) of mainWindow into its own file will therefore be needed.
Good use of a preload.js script dictates setting nodeIntegration: false and contextIsolation: true. Additionally, there should be no need to use any form of remote modules. I have re-worked your preload.js script to be used only as a form of communication between the main process and render process. Various forms of preload.js scripts can be used, but in this instance I have used the most simplified (but not very flexible) approach.
Lastly, not having access to your receiveAndConversion.js file, I have mocked a random hand / position data stream.
As you can see, separating domains into their own files can keep the overall application logical, easy to maintain and bug free when adding additional features.
main.js (main process)
// Require the necessary Electron modules
const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;
// Require the necessary Node modules
const nodePath = require('path');
// Require the necessary Application modules
const appMainWindow = require(nodePath.join(__dirname, './main-window'));
const appReceiveAndConversion = require(nodePath.join(__dirname, './receiveAndConversion'));
// Prevent garbage collection
let mainWindow;
electronApp.on('ready', () => {
mainWindow = appMainWindow.create();
appReceiveAndConversion.run();
});
electronApp.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
electronApp.quit();
}
});
electronApp.on('activate', () => {
if (electronBrowserWindow.getAllWindows().length === 0) {
appMainWindow.create();
}
});
Having the create() and get methods of the mainWindow in its own file allows for inclusion within any other file that need reference to the mainWindow.
main-window.js (main process)
// Require the necessary Electron modules
const electronBrowserWindow = require('electron').BrowserWindow;
// Require the necessary Node modules
const nodePath = require('path');
let mainWindow;
function create() {
mainWindow = new electronBrowserWindow({
x: 0,
y: 0,
width: 800,
height: 600,
show: false,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: nodePath.join(__dirname, './preload.js')
}
});
mainWindow.loadFile('index.html')
.then(() => { mainWindow.show(); })
return mainWindow;
}
function get() {
return mainWindow;
}
module.exports = {create, get}
receiveAndConversion.js (main process)
Mocked...
// Require the necessary Node modules
const nodePath = require('path');
// Require the necessary Application modules
const appMainWindow = require(nodePath.join(__dirname, './main-window'));
let mainWindow;
// Generate a random number
function randomNumber(lower, upper) {
return Math.floor(Math.random() * (upper - lower + 1) + lower)
}
// An infinitely polled function
function listener() {
let hand = (randomNumber(0, 1)) ? 'leftHand' : 'rightHand';
let position = (randomNumber(0, 1)) ? 'opened' : 'closed';
console.log(hand + ' ' + position); // Testing
mainWindow.webContents.send(hand, position);
}
// Called from main.js
function run() {
mainWindow = appMainWindow.get();
setInterval(() => { listener(); }, 350);
}
module.exports = {run}
preload.js (main process)
A simple (but rigid) example.
// Import the necessary Electron components
const contextBridge = require('electron').contextBridge;
const ipcRenderer = require('electron').ipcRenderer;
// Exposed protected methods in the render process
contextBridge.exposeInMainWorld(
// Allowed 'ipcRenderer' methods
'electronAPI', {
// From main to render
leftHand: (position) => {
ipcRenderer.on('leftHand', position);
},
rightHand: (position) => {
ipcRenderer.on('rightHand', position);
}
});
Instead of changing background colors via JavaScript, it is better to change class names or even better again, data attribute values in this instance.
For simplicity, I have incorporated a revised renderer.js between the <script> tags.
index.html.js (render process)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Electron Test</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';"/>
<style>
body {
margin: 0;
padding: 0;
height: 100vh;
display: flex;
flex-flow: row nowrap;
}
#left-hand,
#right-hand {
flex: 1 0 50%;
display: flex;
justify-content: center;
align-items: center;
font-size: 3em;
}
#left-hand[data-position="closed"],
#right-hand[data-position="closed"] {
background-color: darkred;
}
#left-hand[data-position="opened"],
#right-hand[data-position="opened"] {
background-color: darkgreen;
}
</style>
</head>
<body>
<div id="left-hand" data-position="closed">Left Hand</div>
<div id="right-hand" data-position="closed">Right Hand</div>
</body>
<script>
let leftHand = document.getElementById('left-hand');
let rightHand = document.getElementById('right-hand');
window.electronAPI.leftHand((event, position) => {
console.log('leftHand ' + position); // Testing
leftHand.dataset.position = position;
});
window.electronAPI.rightHand((event, position) => {
console.log('rightHand ' + position); // Testing
rightHand.dataset.position = position;
});
</script>
</html>
So I'm experiencing issue when I'm trying to make a window transparent. I made tranparent: true, frame: false but it doesn't really work. It removes the frame and stuff but doesn't do what I want till the end. I want it to be like really transparent. What I get is a: frameless window which is not transparent.
Help would be appreciated. Some code:
main.js
// main.js
// Modules to control application life and create native browser window
const { app, BrowserWindow } = require('electron')
const { maxHeaderSize } = require('http')
const path = require('path')
function createWindow () {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: maxHeaderSize,
height: maxHeaderSize,
transparent:true,
frame: false
})
// and load the index.html of the app.
mainWindow.loadFile('bodycam.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
app.whenReady().then(() => {
function onAppReady() {
createWindow()
app.on('activate', function () {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
}
setTimeout(onAppReady, 300)
})
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
// In this file you can include the rest of your app's specific main process
some part of the code (that affects html body) from style.css (that's being linked with bodycam.html)
body {
margin: 0px auto;
overflow: hidden;
font-family: 'Share Tech Mono', monospace;
font-size: 13px;
}
Why you are facing this issue
In your case, you are facing this issue because you are trying to define the size of the window from the maxHeaderSize value, wich comes from the http Node API. And this... Actually makes no sense. The value of maxHEaderSize is probably way bigger than the size of your screen. Electron seems to be suffering when creating a transparent window that big.
How to fix
You just need to remove that crazy value when creating your BrowserWindow. For example :
const mainWindow = new BrowserWindow({
transparent: true,
frame: false,
})
If you want to set your window at the same size of your screen, you can use the fullscreen option :
const mainWindow = new BrowserWindow({
transparent: true,
frame: false,
fullscreen: true,
})
Finally, if you want your user to be able to "click throught the window", you probably will be interested in the setIgnoreMouseEvents method :
const mainWindow = new BrowserWindow({
transparent: true,
frame: false,
fullscreen: true,
})
mainWindow.setIgnoreMouseEvents(true)
So I have a start button, and once the button is clicked I want it to execute a function.
I know I can execute the function on start of the electron app but is there anyway to say have a start button, and it execute the code on click of the button?
Also I know you can't use node in the browser, and I know Electron uses chromium, but there is still access to node right ?
This is the error I get :
Uncaught Exception:
ReferenceError: document is not defined
index.js
const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('path');
const Bot = require('./bot')
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (require('electron-squirrel-startup')) { // eslint-disable-line global-require
app.quit();
}
const createWindow = () => {
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
preload: "./bot.js"
}
});
// and load the index.html of the app.
mainWindow.loadFile(path.join(__dirname, 'index.html'));
// Open the DevTools.
mainWindow.webContents.openDevTools();
};
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow);
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and import them here.
Here is the bot.js file:
const robot = require('robotjs')
const electron = require('electron')
const ipc = electron.ipcRenderer
const Bot = () => {
const button = document.getElementById('start');
button.addEventListener('click', () => console.log('Click'))
// button.addEventListener('click', function (e) {
// // Get mouse position.
// var mouse = robot.getMousePos();
// // Get pixel color in hex format.
// var hex = robot.getPixelColor(mouse.x, mouse.y);
// console.log("#" + hex + " at x:" + mouse.x + " y:" + mouse.y);
// });
}
module.exports = Bot;
The index.html file :
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello World!</title>
<link rel="stylesheet" href="index.css" />
</head>
<body>
<div class="App">
<div class="Header">
<h1>Checkout-Bot</h1>
</div>
<div class="Wrapper">
<p>Click Start</p>
<button id="start">Start</button>
</div>
</div>
</body>
</html>
Move this line and Bot(); from index.js to index.html:
const Bot = require('./bot')
Change this:
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
});
To this:
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
}
});
Electron has a 'renderer' thread for frontend javascript like button clicks. You can run your Bot code from there if you just include the bot.js file in the bottom of your index.html file:
<script src="./bot.js"></script>
And to allow the use of node you have to set webPreferences.nodeIntegration to true in your browser window:
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
}
})
My assumption is you are preloading that JS file before HTML is rendered therefore there no such button exists to attach an event.
Also, I don't see the Bot method is being called. If you don't call Bot() it's not going to attach anything to your button.
Where do you call it? If you forgot, you should add after the button
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello World!</title>
<link rel="stylesheet" href="index.css" />
</head>
<body>
<div class="App">
<div class="Header">
<h1>Checkout-Bot</h1>
</div>
<div class="Wrapper">
<p>Click Start</p>
<button id="start">Start</button>
</div>
</div>
<script>Bot();</script>
</body>
</html>
I'm working on electron app with multiple windows. Let say I have the main one and a few child windows.
If I create 20 child windows with google.com open from the main process it spawns around 23 Electron processes(one per each window + GPU process + something else) and consumes around 800 MB in total of memory on my Windows 10 machine. Which is obviously a lot.
const {app, BrowserWindow} = require('electron')
let mainWindow
const webPreferences = {
sandbox: true
};
function createWindow () {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences
})
mainWindow.loadFile('index.html')
for (var t = 0; t < 20; t++) {
const childWindow = new BrowserWindow({
webPreferences
})
childWindow.loadURL('https://google.com')
}
}
app.on('ready', createWindow)
Task Manager with 23 Electron processes
I know this is the way Chromium works - each tab is a separate process so if one is broken the whole browser and other tabs are alive. I have no doubt about that but I've noticed one interesting thing. If I use native window.open as described here it mysteriously spawns only 4 processes. Somehow it combines all "window" processes into a single one + GPU + something else which consumes 400 MB in total which is much better result.
const {app, BrowserWindow} = require('electron')
let mainWindow
const webPreferences = {
sandbox: true // without sandboxing it spawns 23 processes again :(
};
function createWindow () {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences
})
mainWindow.loadFile('index.html')
mainWindow.webContents.on('new-window', (event, url, frameName, disposition, options) => {
event.preventDefault()
const win = new BrowserWindow({
...options,
show: false,
webPreferences
})
win.once('ready-to-show', () => win.show())
if (!options.webContents) {
win.loadURL(url) // existing webContents will be navigated automatically
}
event.newGuest = win
})
}
app.on('ready', createWindow)
And index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
<script>
for (var t = 0; t < 20; t++) {
window.open('https://google.com');
}
</script>
</body>
</html>
Task Manager with 4 Electron processes
Is there any way to have only single process for all child windows if I create them from the main process(first snippet)? It would be great if someone could explain why it works that way.
P.S. I'm using electron fiddler with Electron 6.0.2 runtime to run these snippets
Update: affinity is being removed, see https://github.com/electron/electron/pull/26874.
The affinity option does the trick. Windows with the same affinity will be gathered together in a single process.
More details on this feature could be found here
https://github.com/electron/electron/pull/11501
and here
https://electronjs.org/docs/api/browser-window#new-browserwindowoptions
I am have been able to open a new window when i click a button, however, its a new pop up window. How can I have the new window open up in place of the main window?
var app = require('app')
var BrowserWindow = require('browser-window')
var ipc = require('ipc')
app.on('ready', function () {
var mainWindow = new BrowserWindow ({
width: 800,
height: 600
})
mainWindow.loadURL('file://' + __dirname + '/main.html')
//mainWindow.openDevTools() //opens inspect console
var prefsWindow = new BrowserWindow ({
width: 400,
height: 400,
show: false
})
prefsWindow.loadURL('file://' + __dirname + '/prefs.html')
With the code above, a new window pops up. Ive attached a screenshot to show what I mean.
popup window
Instead of that popup window, i want 'prefs' to replace the main window (and other options to replace the main window once added).
Instead of creating a new window, just load the prefs.html into the mainWindow. Your old content (main.html) will get replaced without additional windows opening.
When the respective button is placed inside the main.html you will need to apply this loading via the ipc remote module.
Following this SO answer for Electron 0.35.0 and above:
// In main process.
const ipcMain = require('electron').ipcMain;
// in main process, outside of app.on:
ipc.on('load-page', (event, arg) => {
mainWindow.loadURL(arg);
});
// In renderer process (web page).
const ipc = require('electron').ipcRenderer;
Loading the new page can then be performed as follows:
ipc.send('load-page', 'file://' + __dirname + '/prefs.html');
In case anyone interested, this is what I did.
assuming I have login form and after signing in I wanted to show the main window where things will happen.
setup your index.js
const electron = require('electron');
const url = require('url');
const path = require('path');
const { app, BrowserWindow } = electron;
let loginWindow;
var mainIndex = '../../index.html'; //the login window
var directoryHtml = '../html/'; //directory of where my html file is, the main window is here except the login window
var iconPath = '../../images/logo.png'; //replace with your own logo
let { ipcMain } = electron;
var newWindow = null;
app.on('ready', function () {
loginWindow = new BrowserWindow({//1. create new Window
height: 600, width: 450,
minHeight: 600, minWidth: 450, //set the minimum height and width
icon: __dirname + iconPath,
frame: false, //I had my own style of title bar, so I don't want to show the default
backgroundColor: '#68b7ad', //I had to set back color to window in case the white screen show up
show: false //to prevent the white screen when loading the window, lets not show it first
});
loginWindow.loadURL(url.format({ //2. Load HTML into Window
pathname: path.join(__dirname, mainIndex),
protocol: 'file',
slashes: true
}));
loginWindow.once('ready-to-show', () => {
loginWindow.show() //to prevent the white screen when loading the window, lets show it when it is ready
})
});
//dynamically resize window when this function is called
ipcMain.on('resize', function (e, x, y) {
loginWindow.setSize(x, y);
});
/** start of showing new window and close the login window **/
ipcMain.on('newWindow', function (e, filenName) {
if(newWindow){
newWindow.focus(); //focus to new window
return;
}
newWindow = new BrowserWindow({//1. create new Window
height: 600, width: 800,
minHeight: 600, minWidth: 800,
icon: __dirname + iconPath,
frame: false,
backgroundColor: '#68b7ad',
show: false
});
newWindow.loadURL(url.format({ //2. Load HTML into new Window
pathname: path.join(__dirname, directoryHtml + filenName),
protocol: 'file',
slashes: true
}));
newWindow.once('ready-to-show', () => { //when the new window is ready, show it up
newWindow.show()
})
newWindow.on('closed', function() { //set new window to null when we're done
newWindow = null
})
loginWindow.close(); //close the login window(the first window)
});
/** end of showing new window and closing the old one **/
app.on('closed', function () {
loginWindow = null;
});
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (loginWindow === null) {
createWindow()
}
})
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Login Window</title>
</head>
<body>
<h1>Login</h1>
<!-- . . . . -->
<button id="btn-login" onclick="loginNow()"></button>
<!-- . . . . -->
<script>
function loginNow(){
//.....
//assuming the authentication is valid, we want to show now the new window which will be our main window
const { ipcRenderer } = require('electron'); //require electron
//using ipcRenderer, let's call the function in index.js where the function name is `newWindow`,
//the `main.html` is the new html file I want to show, use your own.
ipcRenderer.send('newWindow','main.html');
}
</script>
</body>
</html>
I don't if this is the right way to do it, and I don't know the disadvantage of doing it like this but I hope none. hope this help someone.
You have a few options.
You could just call prefsWindow.focus() to ensure the second window is on top of the first.
You could hide or close the main window with mainWindow.hide() or mainWindow.destroy(), leaving only the second window open. Then reopen it when your done.
Or instead of having two windows, you could just load your prefs page into the first window, and when done back to the main page.
I had faced a similar issue when creating an application that foremost required authentication before accessing the actual content. So the first and main page of the application was a login form. After the login was successful, a new page should load instead where the actual content was suppossed to be. To do so, i have done the following:
In main.js or index.js how you'd name it, instead of loading the second window at the start and then show it, i load it inside an IPC event listener. So it loads the page when the IPC listener receives a certain event.
const {ipcMain} = require('electron');
ipcMain.on('login', (event, arg) => {
loginPage.loadURL(url.format({
pathname: path.join(__dirname, 'mainpage.html'),
protocol: 'file',
slashes: true
}));
});
Note, that loginPage is my main window that gets created on app.on() and mainpage is the second page that gets created after a successful login.
Then in my loginPage.html, after i verify the login, if it's successful i send that IPC renderer message back to the main process. Which is fairly simple to do:
var ipc = require('electron').ipcRenderer;
ipc.send('login', 'an-argument');
Above method should work. I am just a beginner so i cannot say if it's the best way to do this or if it has any unwanted implication that are not immediately seen, but it's worked out for me so you might as well give it a try.
I was fighting the same issue as you did until I found a simple solution.
Here's the JS code:
const electron = require('electron');
let rootPath = "src/Page/index.html" //Path to the html file
LoadNewWindowInCurrent(rootPath); //Opens new html file in current window
//Here's the ready function for you to use
function LoadNewWindowInCurrent (PathToHtml){
let localWindow = electron.remote.getCurrentWindow();
localWindow.LoadFile(PathToHtml);
}