Home > Mobile >  Making a Confirmation in Electron.js
Making a Confirmation in Electron.js

Time:06-21

I want to make a message box which contains yes and no buttons in a electron.js app. I tried to do it with dialog inside the electron. But it didn't work:

const electron = require('electron')
const { dialog } = electron
console.log(dialog) // undefined
const electron = require('electron')
const dialog = electron.remote.dialog
console.log(dialog) // Uncaught Error: Cannot read "dialog" of undefined (remote is undefined)

Then, I tried to do it with dialog which is a module in npm. But it didn't do the thing that I want to do. There wasn't any yes or no buttons also it returned the same responses when I clicked OK or I closed window:

const electron = require('electron')
const dialog = require('dialog')
dialog.info('Are you sure?', 'Confirmation', function(exitCode) {
        if (exitCode == 0) {
                // Should clicked OK (always response)
        }
        if (exitCode == 1) {
                // Should closed window (but never works)
        }
})

What did I do wrong?

CodePudding user response:

You will want to use Electron's dialog.showMessageBox(); method.

The dialog.showMessageBoxSync(); method would block your main process until a response is received, so you won't want to use that unless intended.


I have placed the creation and management of your dialog box in the main.js file. If you want to move this into its own file, that's not a problem. All you would need to do is get() the (main) window instance if you want your dialog box to be a child of the main window.

main.js (main process)

// Import required Electron modules
const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;
const electronDialog = require('electron').dialog;
const electronIpcMain = require('electron').ipcMain;

// Import required Node modules
const nodePath = require('path');

// Prevent garbage collection
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.on('openDialog', () => {
    electronDialog.showMessageBox(window, {
        'type': 'question',
        'title': 'Confirmation',
        'message': "Are you sure?",
        'buttons': [
            'Yes',
            'No'
        ]
    })
        // Dialog returns a promise so let's handle it correctly
        .then((result) => {
            // Bail if the user pressed "No" or escaped (ESC) from the dialog box
            if (result.response !== 0) { return; }

            // Testing.
            if (result.response === 0) {
                console.log('The "Yes" button was pressed (main process)');
            }

            // Reply to the render process
            window.webContents.send('dialogResponse', result.response);
        })
})

For proper communication between processes, we must use Inter-Process Communication.

preload.js (main process)

// Import the necessary Electron modules
const contextBridge = require('electron').contextBridge;
const ipcRenderer = require('electron').ipcRenderer;

// Exposed protected methods in the render process
contextBridge.exposeInMainWorld(
    // Allowed 'ipcRenderer' methods
    'ipcRenderer', {
        // From render to main
        openDialog: () => {
            ipcRenderer.send('openDialog');
        },
        dialogResponse: (response) => {
            ipcRenderer.on('dialogResponse', response);
        }
    }
);

Finally, your index.html file will listen for a button click. Once clicked, send a message to the main process to open the dialog box.

Once a valid response if received from the dialog box, the response is sent back to the render process for processing.

PS: The render method ipcRenderer.invoke() could be used instead of the ipcRenderer.send() method. But if it was, you would need to handle the "No" or escape (ESC) response in the render process.

index.html (render process)

<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Electron Test</title>
        <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';"/>
    </head>

    <body>
        <input type="button" id="openDialog" value="Show Dialog">

        <hr>

        <div id="response"></div>
    </body>

    <script>
        // Open dialog (in main process) when "Show Dialog" button is clicked
        document.getElementById('openDialog').addEventListener('click', () => {
            window.ipcRenderer.openDialog('openDialog');
        })

        // Response from main process
        window.ipcRenderer.dialogResponse((event, response) => {
            if (response === 0) {
                // Perform your render action here
                document.getElementById('response').innerText = 'The "Yes" button was clicked';
            }
        });
    </script>
</html>

To use more than 2 button in your dialog box(es), in the creation of your dialog box you may want to designate a cancelId and check for all valid return values before actioning anything.

  • Related