tumblewood
tumblewood

Reputation: 73

Electron browser window

I have 2 BrowserWindow instances in my electron application, mainWindow and secondaryWindow. There is a button in mainWindow which when clicked should open secondaryWindow.

Now my issue is that I don't want to be able to click on anything in the mainWindow until the secondaryWindow is closed.

The closest I could get was to use mainWindow.hide() but this just completely hides the window, I want to still see the mainWindow while the secondaryWindow is active but it should be disabled / inactive.

Any suggestions?

Upvotes: 0

Views: 2731

Answers (1)

Rhayene
Rhayene

Reputation: 945

There are 2 ways to open a child window:

1. from the main process:

You can open a child window from the main process. This is for example useful for a custom window in the menu.

Here you can use the constructor to make it a child of parent. If the attribute modal is true, the parent window will not be accessible until the child window is closed.

function createChild(parent, html) {
  //creates modal window
  child = new BrowserWindow({
    width: 786,
    height: 847,
    parent: parent,
    modal: true,
    show: false
  });
  child.loadURL(html);
  child.webContents.openDevTools();
  child.once("ready-to-show", () => {
    child.show();
  });
}

2. from the renderer process

Now, we don't always want to send an event over the IPC to the main process just to open a child window, right?

We don't need to. We can use the open function on our window for that.

For example:

const button = document.querySelector('button')
button.addEventListener('click', e => {
     self.open(`file://${__dirname}/child.html`)
})

To make this window a child of your parent and modal, you can register an eventlistener on the parent window:

parent.webContents.on(
    "new-window",
    (event, url, frameName, disposition, options, additionalFeatures) => {
      Object.assign(options, {
        parent: parent,
        modal: true
      });
    }
  );

With this, when window.open() is called on the parent window, it will open a modal child window.

Example

main.js

const { app, BrowserWindow } = require("electron");

let win;
function createWindow() {
  win = new BrowserWindow({ width: 1000, height: 800 });
  win.loadURL(`file://${__dirname}/index.html`);
  win.webContents.openDevTools();
  win.on("closed", () => {
    win = null;
  });

  win.webContents.on(
    "new-window",
    (event, url, frameName, disposition, options, additionalFeatures) => {
      Object.assign(options, {
        parent: win,
        modal: true
      });
    }
  );
}

app.on("ready", createWindow);

index.html

<!DOCTYPE html>
<html>

<body>
    <p>I am the parent, you can't touch me until you closed my child!</p>
    <button>Open child!</button>
    <script>
        const button = document.querySelector('button')
        button.addEventListener('click', e => {
            self.open(`file://${__dirname}/child.html`)
        })
    </script>
</body>

</html>

child.html

<!DOCTYPE html>
<html>

<body>
    I'm the child!
</body>

</html>

Update Electron 5 or higher

With electron 5 node integration was disabled in the renderer process by default for security reasons. Since this example uses __dirname (which is part of the node API) in the renderer process, we need to reintroduce it, because it is not available anymore. In this example I use a preload script for this purpose:

main.js

const { app, BrowserWindow } = require("electron");

let win;
function createWindow() {
  win = new BrowserWindow({
    width: 1000,
    height: 800,
    webPreferences: {
      preload: `${__dirname}/preload.js`,
    },
  });
  win.loadURL(`file://${__dirname}/index.html`);
  win.webContents.openDevTools();
  win.on("closed", () => {
    win = null;
  });

  win.webContents.on(
    "new-window",
    (_event, _url, _frameName, _disposition, options, _additionalFeatures) => {
      Object.assign(options, {
        parent: win,
        modal: true,
      });
    }
  );
}

app.whenReady().then(createWindow).catch(console.error);

preload.js

window.__dirname = __dirname;

index.html

<!DOCTYPE html>
<html>
  <body>
    <p>I am the parent, you can't touch me until you closed my child!</p>
    <button>Open child!</button>
    <script>
      const button = document.querySelector("button");
      button.addEventListener("click", (e) => {
        self.open(`file://${__dirname}/child.html`);
      });
    </script>
  </body>
</html>

child.html

<!DOCTYPE html>
<html>
  <body>
    I'm the child!
  </body>
</html>

Upvotes: 2

Related Questions