What! Desktop Applications in Javascript!! Electron with Angular4. | 7CTECH

What! Desktop Applications in Javascript!! Electron with Angular4.

Get Quote

What! Desktop Applications in Javascript!! Electron with Angular4.

Even though the era of Windows forms and desktop applications being main stream has long gone, There comes a problem every now and then that can be solved only by proper desktop applications. For example, We at 7CTECH recently faced a case where client needed a desktop application for managing and comparing a lot of CSV files. Yes I understand many of you would be saying that can be done on a web server!. Yes it can , but there was a need that the tool is needed to be available offline as well and it needed to work with proprietary data meaning those files could not be uploaded to a web-server (corporate property and all that).

So the solution was to make a Desktop Application. 7CTECH has been working on Windows-Form and Microsoft WPF for quite a time (around 10 years to be specific) but being a progressive organization we decided to go with a new technology.


The Solution:

Electron and Angular 4 are quite a powerful set if you know how to use it. ElectronJS offers a way to communicate with the local system (OS,File system) here while Angular can be used as the actual work horse and display generator.And should be used like that because once you pass things on to the rendering control (or you may call part) of the application, if not all then most of the operations should happen there rather then main part/file/component or what ever you would like to call it.Also since we are doing this in 2017 and you get all sorts of perks and ease with Typescript we decided to use typescript here as well. So before any time wasting lets get to a small walk through on how to achieve that.


Step-1 (Set-up).

Go to the folder where you want to work and create a file named:

We made the whole tool using Electron Js and hosting Angular-4 inside it.


Package.json

This will be the file that contains your basic dependencies and other configurations. Open up the file and enter following text in that.

"name": "my-cool-electron-app",
"version": "0.0.1",
"description": "Electron js Angular 4 and Typescript",
"homepage": "",
"main": "main.js",
"scripts": {
"start": "electron ."
},
"dependencies": {
"@angular/common": "~4.0.0",
"@angular/compiler": "~4.0.0",
"@angular/core": "~4.0.0",
"@angular/forms": "~4.0.0",
"@angular/http": "~4.0.0",
"@angular/platform-browser": "~4.0.0",
"@angular/platform-browser-dynamic": "~4.0.0",
"@angular/router": "~4.0.0",
"core-js": "~2.4.1",
"ngx-electron": "0.0.11",
"rxjs": "~5.1.0",
"zone.js": "~0.8.4"
},
"devDependencies": {
"@angular/cli": "1.0.0",
"@angular/compiler-cli": "~4.0.0",
"@types/jasmine": "2.5.38",
"@types/node": "~6.0.60",
"codelyzer": "~2.0.0",
"copyfiles": "^1.2.0",
"electron": "1.6.2",
"electron-packager": "~8.6.0",
"electron-prebuilt": "~1.4.13",
"protractor": "~5.1.0",
"ts-node": "~2.0.0",
"tslint": "~4.5.0",
"typescript": "~2.2.0"
}
}

That will install all the dependencies and needed tools for us to move forward.

Open the command prompt or the terminal and go the folder where you want to work and run following command. (We assume that you already have NodeJS installed).

npm install

Done? Good.

Now add these two files as well in the same directory.

tsconfig.json (Configuration for typescript)
tslint.json (Configuration for typescript transpiler)
typings.json (The types data configuration Note that ElectronJS is not written on type script hence you do not have the types related data by default when you install it)

Now add following code in all three of them respectively.

{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"baseUrl": "src",
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es5",
"typeRoots": [
"node_modules/@types"
],
"lib": [
"es2016",
"dom"
]
}
}
{
"rulesDirectory": [
"node_modules/codelyzer"
],
"rules": {
"callable-types": true,
"class-name": true,
"comment-format": [
true,
"check-space"
],
"curly": true,
"eofline": true,
"forin": true,
"import-blacklist": [true, "rxjs"],
"import-spacing": true,
"indent": [
true,
"spaces"
],
"interface-over-type-literal": true,
"label-position": true,
"max-line-length": [
true,
140
],
"member-access": false,
"member-ordering": [
true,
"static-before-instance",
"variables-before-functions"
],
"no-arg": true,
"no-bitwise": true,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-construct": true,
"no-debugger": true,
"no-duplicate-variable": true,
"no-empty": false,
"no-empty-interface": true,
"no-eval": true,
"no-inferrable-types": [true, "ignore-params"],
"no-shadowed-variable": true,
"no-string-literal": false,
"no-string-throw": true,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": true,
"no-unused-expression": true,
"no-use-before-declare": true,
"no-var-keyword": true,
"object-literal-sort-keys": false,
"one-line": [
true,
"check-open-brace",
"check-catch",
"check-else",
"check-whitespace"
],
"prefer-const": true,
"quotemark": [
true,
"single"
],
"radix": true,
"semicolon": [
"always"
],
"triple-equals": [
true,
"allow-null-check"
],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"typeof-compare": true,
"unified-signatures": true,
"variable-name": false,
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type"
],

"directive-selector": [true, "attribute", "app", "camelCase"],
"component-selector": [true, "element", "app", "kebab-case"],
"use-input-property-decorator": true,
"use-output-property-decorator": true,
"use-host-property-decorator": true,
"no-input-rename": true,
"no-output-rename": true,
"use-life-cycle-interface": true,
"use-pipe-transform-interface": true,
"component-class-suffix": true,
"directive-class-suffix": true,
"no-access-missing-member": true,
"templates-use-public": true,
"invoke-injectable": true
}
}
{
"globalDependencies": {
"node": "registry:dt/node#7.0.0+20170322231424"
}
}

Step 2 (Say hello to Electron):

Now since we are all set up. Lets give it a little spin. Go ahead and open index.html that we had made.

Put following code in there:

<html>
<head>
<title>
Hello electron!
</title>
</head>
<body>
<h1>It works for the basic version</h1>
</body>
</html>

Done? great. Now the main stuff starts. Till now all we have done is simply configure the app except making a tiny html display markup (index.html) for our selves.Lets go and write the main file for out app. Main.js but before we do that , go ahead and have a look at the package.json and find this name and you will see we have already configured it to be the "main" entry point for our application.

Now go ahead and make following file:

Main.js

and put following text in there.

'use strict';
const electron = require('electron');
// Module to control application life.
const {app} = electron;
var fs = require('fs');
// Module to create native browser window.
const {BrowserWindow} = electron;

let win;
function createWindow() {

    let electronScreen = electron.screen;
    let size = electronScreen.getPrimaryDisplay().workAreaSize;
    // Create the browser window.
    
    win = new BrowserWindow({
        x: 0,
        y: 0,
        width: size.width,
        height: size.height
    });

    let url = 'file://' + __dirname + '/index.html';
    let Args = process.argv.slice(1);

   
    // and load the index.html of the app.
    win.loadURL(url);

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

    // Emitted when the window is closed.
    win.on('closed', () => {
        // Dereference the window object, usually you would store windows
        // in an array if your app supports multi windows, this is the time
        // when you should delete the corresponding element.
        win = null;
    });
}

// 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.
app.on('ready', createWindow);

// Quit when all windows are closed.
app.on('window-all-closed', () => {
    // On OS X 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 OS X 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 (win === null) {
        createWindow();
    }
});

Here is a short description of what we are doing here:

1-We made a browser Window (the main window where the current view is going to be rendered).We did that in a function.And here we have mentioned the location of the HTML file we want to load initially.

2-On the event of "ready" for the app which means that app is now "ready" to load stuff. We called the function we created in above function.these two steps will render the app all fine.

3-Now we also closed the app using app.quit on the event of 'window-all-closed' for the app. It means when all windows for the current application are closed we are telling the OS to quit the application. This is for OS X since in OS X the operating system keeps the menu of the application active until you quit it completely.

4-For the browser window we had made in the function we had created, We need to make sure that object is properly destroyed and garbage collection services can then clean it up. For that we handle yet another event but this time for browser window and make the said object "null".

There are a lot more events for the app and browser window objects that you can manage and play around here. But for now till this step we have a basic Electron app that is fully functional (we will run it in a moment) and we have a setup in place for the AngularJS 4.

For now go to the command prompt or the terminal window that we had opened initially and put this command in there . (if you closed it some how open it again and navigate to the root folder of your project).

npm start

Congratulations you just made your first electron app. Have some detailed look at the code that we have written and try to play around with it a little.

We will continue to the next step of loading the AngularJS4 application inside the ElectronJS as well as doing some OS level access like file access in next post.

Stay tuned for the next post and update in couple of days.