EaBengaluru
EaBengaluru

Reputation: 71

Why electron defaultPath is not opening the provided directory path

Hi i'm not able to open the provided directory path(/home/userxyz/Releases/alpha) with electron

What i'm trying

  1. i have a path like this on ubuntu /home/userxyz/Releases/alpha

  2. when i try to open this path with below code

const files = await dialog.showOpenDialog({
    title:'Browse mapped drive',
    defaultPath: "/home/userxyz/Releases/alpha",
    properties: ['openFile', 'multiSelections']
});
  1. it is opening some junk directory

Note: i will be having variable let openDirectory = "/home/userxyz/Releases/alpha" which will change based on config value.

Question: i want to open a directory with the provided path let say the path will be /home/userxyz/Releases/alpha

Upvotes: 0

Views: 471

Answers (1)

midnight-coding
midnight-coding

Reputation: 3217

Regarding successfully opening a defaultPath, I have noticed that if the passed-in path does not exist, then either the last opened path or the valid part of the defaultPath (starting from the left) is opened. Therefore, you would want to confirm that the defaultPath exists prior to opening a dialog.

I have included a full but minimised example on how to implement your desired action. Note the use of the preload.js script (via whitelisted channel names only) and the ipcRenderer.invoke(channel, ...args) method in the render process and the ipcMain.handle(channel, listener) method in the main process.


I have used the channel name openFileDialog.

preload.js (main process)

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

// White-listed channels.
const ipc = {
    'render': {
        // From render to main.
        'send': [],
        // From main to render.
        'receive': [],
        // From render to main and back again.
        'sendReceive': [
            'openFileDialog' // Channel name
        ]
    }
};

// Exposed protected methods in the render process.
contextBridge.exposeInMainWorld(
    // Allowed 'ipcRenderer' methods.
    'ipcRender', {
        // From render to main.
        send: (channel, args) => {
            let validChannels = ipc.render.send;
            if (validChannels.includes(channel)) {
                ipcRenderer.send(channel, args);
            }
        },
        // From main to render.
        receive: (channel, listener) => {
            let validChannels = ipc.render.receive;
            if (validChannels.includes(channel)) {
                // Deliberately strip event as it includes `sender`.
                ipcRenderer.on(channel, (event, ...args) => listener(...args));
            }
        },
        // From render to main and back again.
        invoke: (channel, args) => {
            let validChannels = ipc.render.sendReceive;
            if (validChannels.includes(channel)) {
                return ipcRenderer.invoke(channel, args);
            }
        }
    }
);

See below for further use of the preload.js script.

/**
 * Render --> Main
 * ---------------
 * Render:  window.ipcRender.send('channel', data); // Data is optional.
 * Main:    electronIpcMain.on('channel', (event, data) => { methodName(data); })
 *
 * Main --> Render
 * ---------------
 * Main:    windowName.webContents.send('channel', data); // Data is optional.
 * Render:  window.ipcRender.receive('channel', (data) => { methodName(data); });
 *
 * Render --> Main (Value) --> Render
 * ----------------------------------
 * Render:  window.ipcRender.invoke('channel', data).then((result) => { methodName(result); });
 * Main:    electronIpcMain.handle('channel', (event, data) => { return someMethod(data); });
 *
 * Render --> Main (Promise) --> Render
 * ------------------------------------
 * Render:  window.ipcRender.invoke('channel', data).then((result) => { methodName(result); });
 * Main:    electronIpcMain.handle('channel', async (event, data) => {
 *              return await promiseName(data)
 *                  .then(() => { return result; })
 *          });
 */

In this main.js file, one would want to check that the defaultPath exists first, else when the dialog opens it may be unreliable / appear as a random path.

main.js (main process)

const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;
const electronDialog = require('electron').dialog;
const electronIpcMain = require('electron').ipcMain;

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();
    }
});

// ---

// Only pass in a valid defaultPath
let defaultPath = '/home/user/Releases/alpha'; // Ubuntu
// let defaultPath = 'C:\\Users\\user\\invalid\\path'; // Windows

electronIpcMain.handle('openFileDialog', () => {    
    // Dialog options
    let options = {
        title: 'Browse mapped drive',
        defaultPath: defaultPath,
        properties: ['openFile', 'multiSelections']
    };

    // Open dialog
    return electronDialog.showOpenDialog(window, options)
        .then((result) => {
            // Bail early if user cancelled dialog
            if (result.canceled) { return }

            return result.filePaths;
        })
})

Detect button click, send an IPC message to the main thread which opens the dialog. Upon the dialog returning a value, it is returned to the render process and displayed as <li> items.

index.html (render process)

<!DOCTYPE html>
<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="button" value="Open File Dialog">

        <ul id="paths"></ul>
    </body>

    <script>
        document.getElementById('button').addEventListener('click', () => {
            window.ipcRender.invoke('openFileDialog')
                .then((paths) => {
                    if (paths === undefined) { return } // Dialog was cancelled

                    let result = '';

                    for (let path of paths) {
                        result += '<li>' + path + '</li>';
                    }

                    document.getElementById('paths').innerHTML = result;
                })
        })
    </script>
</html>

Upvotes: 1

Related Questions