Open In App

File Upload in ElectronJS

Improve
Improve
Like Article
Like
Save
Share
Report

ElectronJS is an Open Source Framework used for building Cross-Platform native desktop applications using web technologies such as HTML, CSS, and JavaScript which are capable of running on Windows, macOS, and Linux operating systems. It combines the Chromium engine and NodeJS into a Single Runtime. Any native desktop application should integrate itself with the System OS environment. The application should have the ability to interact with core OS functionalities such as the File System, System Tray, etc. Electron provides us with built-in dialog module to display the native System dialogs for interacting with files. This tutorial will use the instance method of the dialog module to demonstrate File Upload functionality in Electron. We assume you are familiar with the prerequisites as covered in the above-mentioned link. For Electron to work, node and npm need to be pre-installed in the system. Dialog Module: The dialog Module is part of the Main Process. To import and use the dialog Module in the Renderer Process, we will be using Electron remote module.

  • Project Structure: Project Structure

Example: We will start by building the Electron Application for File Upload functionality by following the given steps.

  • Step 1: Navigate to an Empty Directory to setup the project, and run the following command,
npm init
  • To generate the package.json file. Install Electron using npm.
npm install electron --save
  • This will install the required node_modules dependencies. Install axios package using npm.
npm install axios --save
  • This package is a Promise based HTTP client for NodeJS. This package is used to make HTTP calls to REST APIs. For more detailed information on axios, Refer this link. Create the sample.txt file in the assets folder for demo purposes. package.json:
{
  "name": "electron-fileupload",
  "version": "1.0.0",
  "description": "File Upload in Electron",
  "main": "main.js",
  "scripts": {
    "start": "electron ."
  },
  "keywords": [
    "electron"
  ],
  "author": "Radhesh Khanna",
  "license": "ISC",
  "dependencies": {
    "axios": "^0.19.2",
    "electron": "^8.2.5"
  }
}
  • Step 2: This is the main.js file. For the Boilerplate code of the main.js file, Refer this link. We have modified the code to suit our project needs. main.js: 

javascript




const { app, BrowserWindow } = require('electron')
 
function createWindow () {
  // Create the browser window.
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: true
    }
  })
 
  // Load the index.html of the app.
  win.loadFile('src/index.html')
 
  // Open the DevTools.
  win.webContents.openDevTools()
}
 
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
// This method is equivalent to 'app.on('ready', function())'
app.whenReady().then(createWindow)
 
// Quit when all windows are closed.
app.on('window-all-closed', () => {
  // On macOS it is common for applications and their menu bar
  // To stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit()
  }
})
 
app.on('activate', () => {
  // On macOS it's common to re-create a window in the 
  // app when the dock icon is clicked and there are no
  // other windows open.
  if (BrowserWindow.getAllWindows().length === 0) {
    createWindow()
  }
})
 
// In this file, you can include the rest of your
// app's specific main process code. You can also
// put them in separate files and require them here.


  • Step 3: Create the index.html file and index.js file within the src directory. We will also copy the boilerplate code for the index.html file from the above-mentioned link. We have modified the code to suit our project needs. index.html: 

html




<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
                           /security#csp-meta-tag -->
    <meta http-equiv="Content-Security-Policy"
          content="script-src 'self' 'unsafe-inline';" />
  </head>
  <body>
    <h1>Hello World!</h1> We are using node
    <script>
         document.write(process.versions.node)
    </script>, Chrome
    <script>
         document.write(process.versions.chrome)
    </script>, and Electron
    <script>
         document.write(process.versions.electron)
    </script>.
 
    <h3>File Upload in Electron</h3>
    <button id="upload">Upload File</button>
     
    <!-- Adding Individual Renderer Process JS File -->
    <script src="index.js"></script>
  </body>
</html>


  • Output: At this point, our application is set up and we can launch the application to check the GUI Output. To launch the Electron Application, run the Command:
npm start
  • Step 4: The Upload File button does not have any functionality associated with it yet. The dialog.showOpenDialog(browserWindow, options) takes in the following parameters.
    • browserWindow: BrowserWindow (Optional) The BrowserWindow Instance. This argument allows the dialog to attach itself to the parent window, making it a modal. A modal window is a child window that disables the parent window. If BrowserWindow is not shown dialog will not be attached to it. In such case It will be displayed as independent window. In the above code, the BrowserWindow instance is not being passed to the dialog, therefore the dialog opens as an independent window on clicking the Upload File button.
    • options: Object It takes in the following parameters,
      • title: String (Optional) The title to be displayed on the dialog window.
      • defaultPath: String (Optional) The directory to be opened as defined by the default path on clicking the Upload File button.
      • buttonLabel: String (Optional) Custom label for the confirmation Button. If empty, the default label will be used. In the above code it is defined as Upload.
      • message: String (Optional) This parameter is supported in macOS only. This is used to display the custom message above input boxes.
      • securityScopedBookmarks: Boolean (Optional) This parameter is supported in macOS only. This parameter is used to create security scoped bookmarks when packaged for the Mac App Store. For more detailed Information, Refer this link.
      • filters: FileFilter[{}] (Optional) It is an Array of Objects. It defines an array of file types that can be displayed or selected when we want to limit the user to a specific type. We can define multiple file types object belonging to different categories. The FileFilter object takes in the following parameters,
        • name: String The name of the category of extensions.
        • extensions: [] The extensions array should consist of extensions without wildcards or dots as demonstrated in the code. To show all files, use the * wildcard (no other wildcard is supported). For more detailed Information, Refer this link.
      • properties: String[] (Optional) Contains a list of features which are available for the native dialog. It  take in the following values,
        • openFile: Allows the Files to be selected.
        • openDirectory: Allows directory/folders to be selected.
        • multiSelections: Allows multiple files to be selected in the dialog.
        • showHiddenFiles: Show Hidden files in dialog.
        • createDirectory: This value is supported in macOS only. It allows creating new directories from within the dialog. In Windows, the context-menu is pre-available in the dialog (right-click in dialog window) and we can create new files and directories from it.
        • promptToCreate: This value is supported in Windows only. This value is used when the filepath entered in the dialog does not exist on the System. At this time, it should prompt the user to create. This does not actually create the file at the path but allows non-existent paths to be returned that can further be created and used by the application.
        • noResolveAliases: This value is supported in macOS only. It disables the automatic resolution of filepath of the alias to its original target. Selected aliases will now return the alias path instead of their target path.
        • treatPackageAsDirectory: This value is supported in macOS only. It treats packages such as .app folders, as a directory instead of a file.
        • dontAddToRecent: This value is supported in Windows only. This value signifies that the file/directory being chosen should not be added to the recent documents list.
    • canceled: Boolean Whether or not the dialog operation was cancelled.
    • filePaths: String[] An Array of filepaths chosen by the user. If the dialog operation is cancelled, it is going to be an empty Array. In case the multiSelections value is not provided in properties, the filePaths array will return a single element.
    • bookmarks: String[] (Optional) This String array is supported in macOS only. This is returned when the securityScopedBookmarks parameter is specified as true in the options Object.
  • Step 5: Once we have obtained the file path from the dialog window, we can follow any of the two approaches:
    • Approach 1: Upload the file to a server by making an HTTP POST REST API call and let the server handle the file processing. We will use the axios package that was installed earlier to achieve this. In index.js file, add the following code just after console.log(global.filepath); } within the Promise index.js: 

javascript




const fs = require('fs');
const axios = require('axios');
 
if (global.filepath && !file.canceled) {
         var formData = new FormData();
         formData.append('file', fs.createReadStream(global.filepath));
         axios.post('[Custom URL]', formData, {
         headers: {
            'Content-Type': 'multipart/form-data'
           }
        });
      }
 
// ...


  • Explanation: We have appended the file to a formData object using the fs module, and set the Content-Type header to multipart/form-data for the POST Request. Replace the [Custom URL] with a URL of the REST API to receive the file on the server side. Once we have received the file on the server side, we can let the server handle the file processing and display the respective response.
  • Approach 2: Process the file on the system itself by reading/manipulating the contents of the file. We can use the fs module to read the contents of the file, and then perform further manipulations as required. In index.js file, add the following code just after console.log(global.filepath); } within the Promise 

javascript




const fs = require('fs');
const fs = require('fs');
 
if (global.filepath && !file.canceled) {
  fs.readFile(global.filepath, {encoding: 'utf-8'}, function(err,data) {
     if (!err) {
          console.log('received data: ' + data);
     } else {
          console.log(err);
      }
   });
 }
 
//...


  • Explanation: We will read the file from the GLOBAL file path variable that was updated from the dialog window with standard UTF-8 encoding. Once we have successfully fetched the contents of the file, we can update/manipulate the contents as per the desired functionality. sample.txt: sample.txt Output:


Last Updated : 25 Aug, 2022
Like Article
Save Article
Previous
Next
Share your thoughts in the comments