'Having trouble adding a callback function from the main.js to the renderer.js after button click in another window
Hi at the moment i have used the ipcRenderer in one of my JS files to execute a function in the main.js. This code executes without a problem. What I'm trying to do straight after is send a callback function to the main renderer.js file so that i can execute another function which manipulates the appearance of some icons in the main window.
main.js code:
ipcMain.on('ReadyBtn', (event) => {
console.log('request received')
ToggleReady();
event.returnValue = "toggle ready test";
})
sidebar.js code - this file is where I'm using the ipc renderer:
const ReadyBtn = document.getElementById('btnReady')
ReadyBtn.addEventListener('click', function(){
ipcRenderer.sendSync("ReadyBtn")
});
The code above works fine, when the button is clicked the toggleReady() function within the main.js file is triggered.
What i would now like to do is set up a call back function in the renderer.js file so that i can execute another function "stateReady()", after the button is clicked. Below is what i have so far:
(async () =>{
await ipcRenderer.invoke('ReadyBtn')
stateReady();
})();
Solution 1:[1]
Noting that you have not included your preload.js
script in your question, I have added the below preload.js
script
which has no concrete implementations in it (apart from the IPC methods), only configuration of whitelisted channel names.
preload.js
(main process)
// Import the necessary Electron components.
const contextBridge = require('electron').contextBridge;
const ipcRenderer = require('electron').ipcRenderer;
// White-listed channels.
const ipc = {
'render': {
// From render to main.
'send': [],
// From main to render.
'receive': [],
// From render to main and back again.
'sendReceive': [
'ReadyBtn' // Channel name
]
}
};
// Exposed protected methods in the render process.
contextBridge.exposeInMainWorld(
// Allowed 'ipcRenderer' methods.
'ipcRender', {
// From render to main.
send: (channel, args) => {
let validChannels = ipc.render.send;
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, args);
}
},
// From main to render.
receive: (channel, listener) => {
let validChannels = ipc.render.receive;
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`.
ipcRenderer.on(channel, (event, ...args) => listener(...args));
}
},
// From render to main and back again.
invoke: (channel, args) => {
let validChannels = ipc.render.sendReceive;
if (validChannels.includes(channel)) {
return ipcRenderer.invoke(channel, args);
}
}
}
);
This preload.js
script is used like so.
/**
* Render --> Main
* ---------------
* Render: window.ipcRender.send('channel', data); // Data is optional.
* Main: electronIpcMain.on('channel', (event, data) => { methodName(data); })
*
* Main --> Render
* ---------------
* Main: windowName.webContents.send('channel', data); // Data is optional.
* Render: window.ipcRender.receive('channel', (data) => { methodName(data); });
*
* Render --> Main (Value) --> Render
* ----------------------------------
* Render: window.ipcRender.invoke('channel', data).then((result) => { methodName(result); });
* Main: electronIpcMain.handle('channel', (event, data) => { return someMethod(data); });
*
* Render --> Main (Promise) --> Render
* ------------------------------------
* Render: window.ipcRender.invoke('channel', data).then((result) => { methodName(result); });
* Main: electronIpcMain.handle('channel', async (event, data) => {
* return await promiseName(data)
* .then(() => { return result; })
* });
*/
In your main.js
file you will use the handle
method to listen for a message on the ReadyBtn
channel, process the request and then return
a response.
main.js
(main process)
const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;
const electronIpcMain = require('electron').ipcMain;
const nodePath = require("path");
let window;
function createWindow() {
const window = new electronBrowserWindow({
x: 0,
y: 0,
width: 800,
height: 600,
show: false,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: nodePath.join(__dirname, 'preload.js')
}
});
window.loadFile('index.html')
.then(() => { window.show(); });
return window;
}
electronApp.on('ready', () => {
window = createWindow();
});
electronApp.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
electronApp.quit();
}
});
electronApp.on('activate', () => {
if (electronBrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
// ---
electronIpcMain.handle('ReadyBtn', (event, message) => {
console.log('Request received'); // Testing
// toggleReady();
return 'Toggle ready test';
})
In your index.html
file, you will use the invoke
method to send
a message on the ReadyBtn
channel to the main process and then
wait for a response.
index.html
(render process)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Electron Test</title>
</head>
<body>
<input id="button" type="button" value="Button">
</body>
<script>
document.getElementById('button').addEventListener('click', () => {
window.ipcRender.invoke('ReadyBtn')
.then((result) => {
console.log(result); // Testing
console.log('Request received'); // Testing
// stateReady();
})
})
</script>
</html>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | midnight-coding |