Reputation: 71
Hi i'm not able to open the provided directory path(/home/userxyz/Releases/alpha
) with electron
What i'm trying
i have a path like this on ubuntu /home/userxyz/Releases/alpha
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']
});
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
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