Unable to set parent window in ElectronJS app


#1

In an electronJS app i’m trying to postMessage from a child window to a parent window. For some reason the window.parent on the child window is not getting set correctly.

let top = new BrowserWindow();
top.loadURL(`file://${__dirname}/app/listen.html`);
let child = new BrowserWindow({parent: top});
child.loadURL(`file://${__dirname}/app/post.html`);
top.show();
child.show();
child.focus();

listen.html

window.addEventListener('message', function(event) {
  console.log('received response:  ', event.data);
}, false);

post.html

window.parent.postMessage('hi','*');

One more thing i noticed is that window.parent in top (and child) is set to itself! That means for both windows below condition is true!

window.parent===window.self

Any suggestions on how to set window.parent correctly in an electron app BrowserWindow()?

[crossposted here]


#2

I’m not experienced with this, but my thoughts are that probably {parent: top} only tells the OS that windows are associated, it doesn’t link them at the JS level, which would require IPC. Perhaps what you want can only be done with iframes or window.open().


#3

ahh, yup i think thats correct.

“The child window will always show on top of the top window.”

So let me rephrase the question, is there anyway to ‘window.postMessage’ from one browser window to another?


#4

Sure, in most of my windows I have the following snippet preloaded into the window.

let electron = require('electron');

function post_ipc_message(message)
    {
    return electron.ipcRenderer.sendSync('ipc_message', message);
    }

function post_ipc_message_async(message)
    {
    electron.ipcRenderer.send('ipc_message_async', message);
    }

/*
Normally the listener would take the form: function listener(event, message){}.
However, because our windows are sandboxed the event parameter is dropped and all we get
is the message parameter, so the listener needs to be: function listener(message){}.
*/
function add_ipc_message_listener(listener)
    {
    electron.ipcRenderer.on('ipc_message', listener);
    }

function remove_ipc_message_listener(listener)
    {
    electron.ipcRenderer.removeListener('ipc_message', listener);
    }

// Inject the permitted resources into the global scope as an object.
global.my_app_name =
    {
    post_ipc_message:               post_ipc_message,
    post_ipc_message_async:         post_ipc_message_async,

    add_ipc_message_listener:       add_ipc_message_listener,
    remove_ipc_message_listener:    remove_ipc_message_listener
    };

You don’t have to preload it, you could just stick in your HTML, but then you’d need to turn on Node integration for the window and this is considered less secure and to be avoided where possible.

Let’s say we had a main window and a preferences window, and you wanted to notify the main that a preference had changed.

In your core NodeJS code simply listen for IPC messages and if needed relay them from one window to another. For example:

function message_handler(event, message)
    {
    switch(message.action)
        {
        }
    }

function message_async_handler(event, message)
    {
    switch(message.action)
        {
        case 'preference_changed':
            // Forward the message on to the main window.
            main_window.send('ipc_message', message);
            break;
        }
    }

electron.ipcMain.on('ipc_message', message_handler);
electron.ipcMain.on('ipc_message_async', message_async_handler);

Then in the main window HTML you have:

// Beware if your window is not sandboxed you'll need to change this to: function listener(event, message)
my_app_name.add_ipc_message_listener(function listener(message)
    {
    if(message.action === 'preference_changed')alert('Preference changed: ' + message.name + ' = ' + message.value);
    }
);

Then in preference window HTML you have:

$('#save_button').on('click', function save_preferences()
    {
    // Notify changes.
    my_app_name.post_ipc_message_async({action: 'preference_changed', name: 'colour', value: '#808080'});
    }
);

Button is clicked, message goes to NodeJS code, message is then forwarded and received by code in main window.

Hope that helps.


#5

Thanks erikwallace-lewdewe. My solution was a little different but involved preload script.