Skip to main content

Command Palette

Search for a command to run...

Getting started with Electron.js and Angular

Published
4 min readView as Markdown
M

Hello, I’m Maulik Sompura, a fullstack Javascript developer. I have a passion for building web applications using Node JS, React, Vue, and various databases and APIs. I can implement business logic, RESTful services, and responsive UIs from Figma designs. I am proficient in GraphQL and Express along with Infrastructure management. I have had the opportunity to work with a variety of technologies including Node JS, React JS, Vue JS, Typescript, Firebase, AWS (various services), Stripe, Cloudinary, PHP, Angular JS, ElectronJS, and ElasticSearch. I am passionate about learning new things and sharing my knowledge with others. I write about Javascript, web development, and other topics on my blog. You can also find me on Linkedin, Github, and Skype. Feel free to reach out to me if you have any questions or feedback. Thanks for reading!

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