'Not able to connect to MySQL database from Electron application
I have started learning electron js application development, so I have created a simple electron js application and I am trying to get data from the MySQL database display it on the HTML page. In the developer console, inside the MySQL connection object state is disconnected. am able to get an alert which is renderer.js file and dbmgr.js file.
Package.json
{
"name": "myfirstelectronapp",
"version": "1.0.0",
"description": "My first electron app",
"main": "main.js",
"scripts": {
"start": "electron ."
},
"author": "Pradeep",
"license": "MIT",
"dependencies": {
"electron": "^17.1.2",
"mysql": "^2.18.1"
}
}
index.html
<body>
<h1>My First Electron application get started</h1>
<div id="names"></div>
<script src="renderer.js"></script>
</body>
renderer.js
document.addEventListener('DOMContentLoaded', async () => {
alert('renderer.js');
let names = window.api.getData();
console.log(names);
let divId = document.getElementById("names");
let namestring = names.join("<br> /");
divId.innerHTML = namestring;
});
preload.js
const dmmgr=require("./models/dbmgr");
const {contextBridge}=require('electron');
const getData=()=>{
return dmmgr.getData();
}
contextBridge.exposeInMainWorld("api",{
getData : getData
})
main.js
const electron = require('electron');
const path = require('path');
const { app, BrowserWindow } = electron;
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, './preload.js')
}
})
win.loadFile("index.html");
}
app.whenReady().then(() => {
createWindow();
});
app.on('window-all-closed', () => {
if (process.platform != 'darwin') app.quit();
})
dbmgr.js
code connect mysql
var mysql = require('mysql');
// Add the credentials to access your database
var connection = mysql.createConnection({
host: 'localhost',
port:'3306',
user: 'root',
password: 'root', // or the original password : 'apaswword'
database: 'vs_users_temp'
});
// connect to mysql
connection.connect(function (err) {
// in case of error
if (err) {
console.log("Error "+err.code);
console.log("Error "+err.sqlMessage);
}
});
exports.getData = () => {
alert('dbmgr.js');
console.log(connection);
// Perform a query
$query = 'SELECT * FROM user';
connection.query($query, function (err, rows, fields) {
if (err) {
console.log("An error ocurred performing the query.");
console.log(err);
return;
}
console.log("Query succesfully executed", rows);
return rows;
});
}
// Close the connection
connection.end(function () {
// The connection has been closed
});
Solution 1:[1]
If you are wanting to render data within your index.html file immediately after it has loaded then you could use win.webContents.send(channel, ...args); once the application is ready and the window is loaded. This is like pushing the data from the main thread instead of pulling it from the render thread (via your existing preload.js script).
Additionally, implementing concrete functions within your preload.js script can be difficult to understand and implement successfully. Instead, I find the approach of using the preload.js script as a gateway to communicate between the main thread and render thread(s) via the use of channel names to be much simpler to understand and implement.
In this preload.js script, one only needs to specify their whitelisted channel name(s). These channel names are used to identify within the main thread and render threads defined lines of communication (with optional data).
In the below preload file I have defined the channel name db:getData. You can use any channel name you like.
preload.js (main thread)
// 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': [
'db:getData' // Channel name
],
// From render to main and back again.
'sendReceive': []
}
};
// 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);
}
}
}
);
Once the application is ready and the window has been loaded, send a message using the channel name db:getData to the render thread along with the accompanying result set from the database.
main.js (main thread)
const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;
const nodePath = require("path");
const dbmgr = require(nodePath.join(__dirname, 'dbmgr'); // Include your dbmgr module
// 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.webContents.send('db:getData', dbmgr.getData()); }) // Send data to render
.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();
}
});
For simplicity, I have the Mysql connect and end functions within the called getData() function (which is exported for use in the main.js file).
Though I haven't used the
mysqlpackage before, I believe pooling connections is highly recommended.
dbmgr.js (main thread)
const mysql = require('mysql');
// Add the credentials to access your database
const connection = mysql.createConnection({
host: 'localhost',
port:'3306',
user: 'root',
password: 'root', // or the original password : 'apaswword'
database: 'vs_users_temp'
});
function getData() => {
// connect to mysql
connection.connect(function (err) {
// in case of error
if (err) {
console.log('Error ' + err.code);
console.log('Error ' + err.sqlMessage);
}
});
console.log(connection); // Testing
// Perform a query
$query = 'SELECT * FROM user';
connection.query($query, function (err, rows, fields) {
if (err) {
console.log('An error ocurred performing the query.');
console.log(err);
return;
}
console.log('Query succesfully executed', rows); // Testing
// Close the connection
connection.end(function () {});
return rows;
});
}
module.exports = { getData }
For the sake of simplicity I have included your renderer.js code within your index.html <script> tags.
Placing your
<script>tag(s) (whether it is importing or inline) just below the closing</body>tag is best practice.
index.html (render thread)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>My First Electron application get started</h1>
<div id="names"></div>
</body>
<script>
window.ipcRender.receive('db:getData', (names) => {
console.log(names); // Testing
let divId = document.getElementById('names');
let namestring = names.join("<br> /");
divId.innerHTML = namestring;
});
</script>
</html>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | midnight-coding |
