Reputation: 79
I'm trying to make a Dialog box pop up with custom "Form" based on what is currently shown in the main process. For instance: if I have a table called "Workout" displayed on the Main Window, then when pressing a button, I want to display a modal window which has input fields that correspond to said Workout, when the user has inputted whatever it is they want to input, I then want them to be able to press Enter and/or have a button which will close said modal window and then send the information to either the Main or Rendering process.
The way I wanted to do this is by creating an empty BrowserWindow to represent the Dialog box, then it'll check what is the currently shown table. If the table is "Workout", then inject some HTML into the browser window so that there's 3 input fields with specific minimums, maximums, etc.
I tried doing this (without checking for the current table, just to see if I can even inject HTML)
let child = new BrowserWindow({modal: true, width: 400, height: 300, show: false});
child.loadURL(url.format({
pathname: path.join(__dirname, 'modal.html'),
protocol: 'file',
slashes: true
}))
child.document.getElementById('textHere').innerHTML += `<input ...>`;
child.once('ready-to-show', () => {
child.show();
})
child.setTitle(currTable);
But it doesn't seem to add anything, in fact, when I try to do this, I get an error that says 'cannot read "getElementById" of undefined'.
I thought that, perhaps, this is because I try to add the element before child.show() is ran, so I tried putting the ... += <input ...>
after the child.show(), but I got the same problem.
EDIT;SOLUTION: The problem was that I didn't understand the IPC communication, I still struggle with the implementation, but here how it'll work for anyone else struggling.
You have main.js which creates your first BrowserWindow, this BrowserWindow loads an HTML file called foo.html [can be done with .loadURL], which has this inside of it:
<script>require('./foo.js');</script>
This means that foo.js is officially the Renderering process in charge of foo.html, and so, if you want to manipulate foo.html, you would have to go through foo.js.
Now for the scenario, I have a button on foo.html. The button has an onClick event handler in foo.js. If I want a new window to be popped up on the screen when the button is clicked [remember that the MAIN process, in this case, main.js (because it's the one who create the first ever BrowserWindow) is in charge of all BrowserWindow management], then I want to, onClick, send a signal to main.js telling it to create a new BrowserWindow, I'll do this like this inside of the button handler in foo.js:
ipcRender.send('message', data);
Now, the main process can receive the signal if you add a corresponding "receiver" in the main process:
ipcMain.on('message', function(event, arg){
//Do What you want based on the args, for instance one could specify that it's a dialog box
//Data is one of the args(Not 10000% sure of this but think so)
}
After you've created the BrowserWindow and loaded the URL, you can send back a message to the Renderer process by doing windowName.webContents.send('message', data);
. Now you've got to receive this message sent from main process, to receive it, do ipcRender.on('message', function(){} //); //This function could already be predefined, like loadXDialog, loadYDialog, etc.
And you're done!
NOTE: Don't hesitate to correct me if I did something wrong, I have received a very nice explanation from someone on Reddit, and I tried to reapply it to my situation and I hope it helps out!
Upvotes: 2
Views: 3381
Reputation: 46
I think it's better to think about the renderer process as all of the files linked by the html files it loaded (css/js/images etc...). The main process "has control" over the renderer process, in that it can open it, close it, and send messages to it. The renderer process itself is just html that runs when that renderer process is shown.
Your scenario seems like it will work fine, but here are the general rules to remember:
Here is some example code of sending information from one browser window to another:
popup.html
<body>
some html ....
<script>
{ ipcRenderer } = require('electron')
ipcRenderer.send("popup-message", "this is a message")
</script>
</body>
main.js
ipcMain.on('popup-message', (msg) => {
mainWindow.webContents.send('popup-message-from-main', msg)
})
index.html (loaded by mainWindow)
<body>
some html ....
<script>
{ ipcRenderer } = require('electron')
ipcRenderer.on('popup-message-from-main', (msg) => {
// do something with msg
})
</script>
</body>
(This can be modified for your example by waiting for input in popup.html and then sending that to main.js)
Upvotes: 3