Getting started with Electron.js and Angular

Do you know about Electron API (a GitHub repository, helping a web developer to make standalone cross-platform app)? The electron can make any web app to Desktop Application in all three major OS (i.e. Windows, Mac, Linux). Okay, enough intro about Electron, let's move on Problem...
So, if you are an Angular Developer and you want to make a Desktop app having a database in MySQL, you came to the right place!
The Directory structure should look like this:
AngularElectronMySQL ->
-Electron
-WebApp (Angular app)
-Setup
So, First Initialize your Angular project using angular-cli (you can also build it simply). Here, I am assuming that you completed your Angular Project and Built it. Just one more thing add a data-service for getting data from MySQL. Subscribe to the MySQL server (for our case: http://localhost:1024). After that, you need to copy the files from the built project to electron folder. I used npm like this:

// copy.js
const fs = require('fs-extra')
var del = require("delete");

//delete js
console.log("Deleting Old JS");
del.sync('../electron/main.*.js', {
  force: true
});
console.log("Deleted");

// copy files
try {
  console.log('Copy started');
  fs.copySync('./dist/', '../electron/');
} catch (ex) {
  console.log('Error : ' + ex);
} finally {
  console.log('Copied');
}

Now, for Electron create a main.js file inside the Electron folder. Write down this code:

// main.js
const setupEvents = require('./installers/setupEvents')
if (setupEvents.handleSquirrelEvent()) {
  // squirrel event handled and app will exit in 1000ms, so don't do anything else
  return;
}
const {
  app,
  BrowserWindow,
  ipcMain
} = require('electron')
const path = require('path')
const url = require('url')
var server = require("./mysql");

let win

function createWindow() {
  win = new BrowserWindow()

  // load the dist folder from Angular
  win.loadURL(url.format({
    pathname: path.join(__dirname, 'index.html'),
    protocol: 'file:',
    slashes: true
  }));

  win.maximize();

  // Open the DevTools optionally:
  // win.webContents.openDevTools();

  win.on('closed', () => {
    win = null
  });

  // console.log(win.webContents.executeJavaScript('alert("world!");send();'));
}

console.log("ipc");
ipcMain.on('synchronous-message', (event, arg) => {
  console.log(arg); // prints "ping"
  event.returnValue = 'pong';
});

app.on('ready', createWindow)


app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', () => {
  if (win === null) {
    createWindow()
  }
})

Now, for connecting with MySQL, we need to create a Node.JS mini server. create a mysql.js file inside Electron folder.

// mysql.js
var http = require("http");
var mysql = require("mysql");
var fs = require("fs");
var jsonContent = null;
const prompt = require('electron-prompt');
var userdata = {
  "host": '',
  "port": '',
  "username": '',
  "password": '',
  "database": ''
};

onLoad();

function onLoad() {
  // console.log("main window : " + mainWindow);
  var connection = null;
  try {

    //This will prompt user for Database details one time.
    var contents = fs.readFileSync(process.env.APPDATA + "/Mcare/sql-config.json");
    jsonContent = JSON.parse(contents);
    connection = mysql.createConnection({
      host: jsonContent.host,
      port: jsonContent.port,
      user: jsonContent.username,
      database: jsonContent.database,
      password: jsonContent.password,
      debug: false
    });
  } catch (ex) {
    var dummy = JSON.stringify(userdata);
    fs.writeFileSync(process.env.APPDATA + "/AngularElectronMySQL/sql-config.json", dummy);
    onLoad();
  }
  connection.connect(function (err) {
    if (err) {
      console.error("error connecting: " + err.stack);

      prompt({
          title: 'Sql Config',
          label: 'Host:',
          value: jsonContent.host,
          inputAttrs: {
            type: 'text'
          },
          type: 'input',
        })
        .then((h) => {
          if (h) {
            userdata.host = h;
            prompt({
                title: 'Sql Config',
                label: 'Port:',
                value: jsonContent.port,
                inputAttrs: {
                  type: 'text'
                },
                type: 'input',
              })
              .then((p) => {
                if (p) {
                  userdata.port = p;
                  prompt({
                      title: 'Sql Config',
                      label: 'Username:',
                      value: jsonContent.username,
                      inputAttrs: {
                        type: 'text'
                      },
                      type: 'input',
                    })
                    .then((u) => {
                      if (u) {
                        userdata.username = u;
                        prompt({
                            title: 'Sql Config',
                            label: 'Password:',
                            value: jsonContent.password,
                            inputAttrs: {
                              type: 'password'
                            },
                            type: 'input',
                          })
                          .then((w) => {
                            userdata.password = w;
                            prompt({
                                title: 'Sql Config',
                                label: 'Database:',
                                value: jsonContent.database,
                                inputAttrs: {
                                  type: 'text'
                                },
                                type: 'input',
                              })
                              .then((d) => {
                                if (d) {
                                  userdata.database = d;
                                  var json = JSON.stringify(userdata);
                                  fs.writeFileSync(process.env.APPDATA + "/Mcare/sql-config.json", json);
                                  onLoad();
                                }
                              })
                              .catch(console.error);
                          })
                          .catch(console.error);
                      }
                    })
                    .catch(console.error);
                }
              })
              .catch(console.error);
          }
        })
        .catch(console.error);
    } else {
      connection.end();
      console.log("connected as id " + connection.threadId);
      afterLoad();
    }
  });
}

function afterLoad() {
  http
    .createServer(function (req, res) {
      var taskQueue = [];
      var token = 0;

      function checkExecuteFinished(queue) {
        if (queue.length == 0) {
          res.setHeader("Content-Type", "application/json");
          res.write(JSON.stringify(data, null, 4));
          res.end();
        }
      }

      function readDataFromMySql(query, fn) {
        taskQueue.push(token++);
        var connection = mysql.createConnection({
          host: jsonContent.host,
          port: jsonContent.port,
          user: jsonContent.username,
          database: jsonContent.database,
          password: jsonContent.password,
          debug: false
        });
        connection.connect(function (err) {
          if (err) {
            console.error("error connecting: " + err.stack);
            return;
          }

          console.log("connected as id " + connection.threadId);
        });
        connection.query(query, function (error, results, fields) {
          if (error) throw error;
          fn(results);
          connection.end();
        });
      }

    var data = [];
      function cleanData() {
        data = {
          id: "",
          name: ""
        };
      }

    function getData(results) {
        for (var i = 0; i < results.length; i++) {
            cleanData();
            data.id = results[i].Id;
            data.name = results[i].Name;
          }
        }
        taskQueue.shift();
        checkExecuteFinished(taskQueue);
      }

      readDataFromMySql("select * from table", getData);

      // console.log(JSON.stringify(location));
    })
    .listen(1024);
}

That's it!! Run your Electron App. The first time it will prompt you for the database credential and then it'll store it in a local file.
Here's the list of required npm dependencies to install:
For Node: http, mysql, electron-prompt
For Copy.js : fs-extra, delete


Did you find this article valuable?

Support Maulik Sompura by becoming a sponsor. Any amount is appreciated!