So, I am pretty new to Electron and wanted to build a desktop application. But I have been running into issues, particularly in getting the renderer and main processes to communicate. I am aware of the IPC and remote concepts and this about me not being able to use them in the first place. I have tried to surf through a lot of related questions before deciding to post here. To be more specific, I have a form(HTML) that needs to be filled out and saved to a local database(sqlite) which I originally planned to access from within the HTML but couldn’t. Therefore, I went for a renderer.js and included that as a script to the HTML, which also failed(couldn’t use ‘require’)- I had nodeintegration turned on during both times. Here are the other solutions tried with no luck so far:
A preload.js script : From what I imagined, I would be able to include my ‘require’ statements here but the problem came when I tried to access DOM elements since I had to register the IPC events
I finally went for the browserify tool after learning that it could bundle all necessary modules and make them available to the renderer. Here too, I followed the procedures stated (https://github.com/browserify/browserify#usage), but just couldn’t get it to work with a whole bunch of new errors being thrown (TypeError: fs.existsSync is not a function, RangeError) and I am still getting the dreaded ‘require’ is not defined error in the browser.
I am basically at an impasse now and don’t know where to go from here. I can share some code here if necessary. Any help will be greatly appreciated.
main.js
const MainDAO = require('./dao/appDAO') const {ipcMain} = require('electron') const electron = require('electron') const { app, BrowserWindow, Menu } = require('electron') const path = require('path') //const template = require('./js/templates') //const employeeReg = require('./assets/js/employeeReg') const dbPath = 'Model/lunaDb' const dialog = electron.dialog let lunaDB = new MainDAO(dbPath); /************************************************************************** */ /*************Login Page ****************************************************************************/ function createSignInWindow() { // Create the browser window. let signIn = new BrowserWindow({ width: 800, height: 520, icon: __dirname + '/img/logo.png', webPreferences: { nodeIntegration: true, } }); //Load signin window signIn.loadFile('view/signin.html') //remove menu list signIn.removeMenu();}
register.html: This is where I first wanted to save form data to sqlite database
<script src="../dist/bundle.js"></script> <script> var currentTab = 0; // Current tab is set to be the first tab (0) showTab(currentTab); // Display the current tab function showTab(n) { // This function will display the specified tab of the form ... var x = document.getElementsByClassName("tab"); x[n].style.display = "block"; // ... and fix the Previous/Next buttons: if (n == 0) { document.getElementById("prevBtn").style.display = "none"; } else { document.getElementById("prevBtn").style.display = "inline"; } if (n == (x.length - 1)) { document.getElementById("nextBtn").innerHTML = "Submit And Again"; } else { document.getElementById("nextBtn").innerHTML = "Next"; } // ... and run a function that displays the correct step indicator: fixStepIndicator(n) } function nextPrev(n) { // This function will figure out which tab to display var x = document.getElementsByClassName("tab"); // Exit the function if any field in the current tab is invalid: if (n == 1 && !validateForm()) return false; // Hide the current tab: x[currentTab].style.display = "none"; // Increase or decrease the current tab by 1: currentTab = currentTab + n; // if you have reached the end of the form... : if (currentTab >= x.length) { window.location.reload(); //...the form gets submitted: alert("Succesfully Added"); // document.getElementById("regForm").submit(); return false; } // Otherwise, display the correct tab: showTab(currentTab); } function validateForm() { // This function deals with validation of the form fields var x, y, i, valid = true; x = document.getElementsByClassName("tab"); z = x[currentTab].getElementsByClassName("needs-validation"); y = x[currentTab].getElementsByTagName("input"); var validation = Array.prototype.filter.call(z, function (form) { form.classList.add("was-validated"); switch (currentTab) { case 0: var name = document.querySelector('#inputName'); var email = document.querySelector('#inputEmail'); var phone = document.querySelector('#inputPhoneNo') if ((email.checkValidity() == false) || (name.checkValidity() == false) || (name.checkValidity() == false)) { valid = false; } break; case 1: var name = document.querySelector('#inputContactName'); var phone = document.querySelector('#inputContactPhoneNo'); if ((name.checkValidity() == false) || (phone.checkValidity() == false)) { valid = false; } break; case 2: var position = document.querySelector('#inputPosition'); var salary = document.querySelector('#inputBasicSalary'); var hiringDate = document.querySelector('#inputHiringDate') if ((position.checkValidity() == false) || (salary.checkValidity() == false) || (hiringDate.checkValidity() == false)) { valid = false; } break default: break; } }); if (valid) { document.getElementsByClassName("step")[currentTab].className += " finish"; } return valid; // return the valid status } function fixStepIndicator(n) { // This function removes the "active" class of all steps... var i, x = document.getElementsByClassName("step"); for (i = 0; i < x.length; i++) { x[i].className = x[i].className.replace(" active", ""); } //... and adds the "active" class to the current step: x[n].className += " active"; } </script> <script src="../assets/js/register.js"></script>
register.js(renderer): require is not defined
const ipc = require('electron').ipcRenderer const submitEmplForm = document.getElementById('nextBtn')
preload.js : when i try to access the DOM components here, it complains of being null that is why I tried adding the require(‘./register)…that didn’t work either
const { ipcRenderer } = require('electron') const emp = require('./register') const _setImmediate = setImmediate const _clearImmediate = clearImmediate process.once('loaded', () => { global.setImmediate = _setImmediate global.clearImmediate = _clearImmediate }) const submitEmplForm = document.querySelector('nextBtn') submitEmplForm.addEventListener('click', function (event) { ipcRenderer.send('asynchronous-message', 'ping') }) ipcRenderer.on('asynchronous-message', function (event, args) { event.preventDefault() console.log('event is ' + event) console.log(args) })
There is also of course the bundle.js file from browserify.
Advertisement
Answer
I finally managed to access the required modules and the DOM elements from within the renderer.js file after carefully creating a new file, starting out with the bare minimum and adding more code incrementally to isolate where the problem was. To be perfectly honest, I did not do anything much differently other than get rid of the preload script, turn on nodeIntegration again and like I mentioned, create a new renderer file and link that to the HTML as the script. That did the trick and now the main and UI can communicate through IPC. Since this is merely a desktop application, I am hoping any security issues associated with turning on nodeIntegration won’t be much of a problem.