I am trying to send data from a main window to another window in electronJS.
How my app works is there is a main window with many selections. On clicking each selection, a new window will open, and the window will show data that is related to that selection. For now, what works is that clicking each selection will open a new window, but I am unable to pass data over to the new window.
I have read through the electron docs but most seem to be focused on data from renderer to main. The example which shows data passing from main to renderer didn't help me and I still struggle to implement what I want.
I tried looking for some help here
Trying to send data from one electron window to another via ipc
Electron: How to securely inject global variable into BrowserWindow / BrowserView?
Electron: How to pass the message/data from preload to renderer?
and tried to implement the suggestions but I still can't get it to work.
I have 2 html files (index.html and details.html), a main.js, a preload.js and a renderer.js for the details.html
Here are my codes:
main.js
// main.js
// Modules to control application life and create native browser window
const { app, BrowserWindow, ipcMain } = require('electron')
const path = require('path')
const createWindow = () => {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 1000,
height: 1000,
webPreferences: {
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(() => {
createWindow()
ipcMain.on('open-selection-window', (event) => {
openNewWindow()
})
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.
const openNewWindow = () => {
const Window = new BrowserWindow({
width: 1000,
height: 1000,
title: ' details',
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
Window.loadFile('details.html')
}
preload.js (note the contextbridge portion)
// preload.js
const axios = require('axios');
const { contextBridge, ipcRenderer } = require('electron');
// All of the Node.js APIs are available in the preload process.
// It has the same sandbox as a Chrome extension.
// this function is called when the user clicks on a selection, it will get the details
const getselectionDetail = (argument) => {
axios.get(`http://apiurl/${argument}`)
.then(response => {
return response.data;
})
}
// this function is called when user press search button, it will search for the selections thru API call,
// and then display the results,
// set onclick function for each result,
const searchselections = (text) => {
//use axios to make a get request to the url
axios.get(`http://apiurl/${text}`)
.then(response => {
const selections = response.data;
// for each element in selections, append a div with the class of search-result and append the html
selections.forEach(selection => {
document.getElementById('results').innerHTML = `
<div >
<p>${selection.name}</p>
</div>`;
});
// for each search result, need to set it such that on click, the contextbridge will send the selection details to the renderer
// and then the renderer will load the selection details
const searchResults = document.getElementsByClassName('search-result');
for (let i = 0; i < searchResults.length; i ) {
searchResults[i].onclick = () => {
contextBridge.exposeInMainWorld(
'selection',
// this is to get a new window to open and sends data to the main process
ipcRenderer.send('open-selection-window', getselectionDetail(selections[i].name))
);
// send data to the renderer -> this doesn't work?
contextBridge.exposeInMainWorld(
'details',
getselectionDetail(selections[i].name)
)
}
}
})
.catch(error => {
console.log(error);
}
)
}
renderer.js
const detail_name = document.getElementById('detail-name');
// load the data from window, need to append to html
console.log(window.details) <-- this doesn't work
index.html
<!--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>Search function</title>
</head>
<body>
<h1>Search function</h1>
<div >
<!-- text input for the search -->
<input type="text" id="search-input" placeholder="Search">
<!-- search button -->
<button id="search-button" type="button">
Search
</button>
</div>
<!-- div to display the search results -->
<div id="results"></div>
</body>
</html>
details.html
<!--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>Details</title>
</head>
<body>
<h1>Details</h1>
<div >
<!-- div for name -->
<div >
<h5>Name:</h5>
<p id="detail-name"></p>
</div>
</div>
<!-- You can also require other files to run in this process -->
<script src="./renderer.js"></script>
</body>
</html>
I appreciate any tips/guidance!
CodePudding user response:
You can use BroadcastChannel like below
const qr = new BroadcastChannel("test");
qr.postMessage(JSON.stringify({ var: "val" }));
and listen from another file like
const bc = new BroadcastChannel("test");
bc.onmessage = (event) => {
this.data = JSON.parse(event.data);
};
You can read more about this on mdn.broadcastchannel
CodePudding user response:
The comments can't hold so much text so I'll post the code here to show what I've tried, but doesn't work.
I added the top code in the onclick assignment preload.js
// for each search result, need to set it such that on click, the contextbridge will send the selection details to the renderer
// and then the renderer will load the selection details
const searchResults = document.getElementsByClassName('search-result');
for (let i = 0; i < searchResults.length; i ) {
searchResults[i].onclick = () => {
contextBridge.exposeInMainWorld(
'selection',
// this is to get a new window to open and sends data to the main process
ipcRenderer.send('open-selection-window', getselectionDetail(selections[i].name))
);
const qr = new BroadcastChannel("test");
qr.postMessage(JSON.stringify({ var: "val" }));
}
}
renderer.js
// set windows onl oad event
window.addEventListener('load', () => {
const bc = new BroadcastChannel("test");
bc.onmessage = (event) => {
this.data = JSON.parse(event.data);
console.log(JSON.parse(event.data));
};
});