Electron + AngularJS - Creating sample application

This is second part of introduction series to create application with Electron and AngularJS.

If you've missed, check out how to prepare dev environment.

For demonstration purposes, through the course of this introduction series I'll be progressively build Todo application.

The big picture

This Todo app does not (and probably) will not be perfect. What I want to concentrate is to go through underlying structure and how it works on Electron platform. I'm working with AngularJS, but you could switch to use any framework you'd like, just install different dependencies.

Short version

In other words, explore on your own.

Longer version

First, let's take a look at project files:

[ea-todo]
├── [app]
    ├── [scripts]
        ├── ...
        ├── index.js
    ├── [styles]
    ├── index.html
├── ...
├── main.js
├── package.json

You probably guessed that I'll explain only key files here:

  • package.json
  • main.js
  • index.html
  • index.js

package.json

There are ton of resources on the web and its better to link to some then write all stuff all over again:

main.js

This is an entry point to our application. In Electron starting point is a JavaScript file where you create your windows. This is also a place where your main application thread lives. When you create window, it has its own renderer thread which has limited access to Node stuff (how to communicate between threads).

const electron = require('electron');  
const app = electron.app;  
const BrowserWindow = electron.BrowserWindow;

// Keep reference of main window because of GC
var mainWindow = null;

// Quit when all windows are closed
app.on('window-all-closed', function() {  
    app.quit();
});

// When application is ready, create application window
app.on('ready', function() {

    // Create main window
    // Other options available at:
    // http://electron.atom.io/docs/latest/api/browser-window/#new-browserwindow-options
    mainWindow = new BrowserWindow({
        name: "ea-todo",
        width: 400,
        height: 600,
        toolbar: false
    });

    // Target HTML file which will be opened in window
    mainWindow.loadURL('file://' + __dirname + "/app/index.html");

    // Uncomment to use Chrome developer tools
    // mainWindow.webContents.openDevTools({detach:true});

    // Cleanup when window is closed
    mainWindow.on('closed', function() {
        mainWindow = null;
    });

});

The point here is to create main application window when Electron app is ready. We point that window to load index.html as content. Also, we removed toolbar since we don't need it in our app.

I commented out (but left it on purpose) code to open Chrome developer tools. If you provide it with detach property, it will lunch dev tools as a separate window. For me it, this is a better way so that UI is not screwed up.

I've also set to quit application if there are no active windows.

If you would add some more application logic needing to access Node API from main thread, you could add it here, or better yet, organise it by spreading your code logically in multiple JS files.

index.html

Our window needs some UI goodness, and that entry point in our index.html file. It consists of loading AngularJS, Angular Material and loading our CSS and JS files.

<!DOCTYPE html>  
<html>  
<head>  
    <title>EA Todo</title>

    <link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Roboto:400,500,700,400italic'>
    <link rel="stylesheet" type="text/css" href="../bower_components/angular-material/angular-material.css">
    <link rel="stylesheet" type="text/css" href="styles/app.css">

    <script type="text/javascript" src="../bower_components/angular/angular.js"></script>
    <script type="text/javascript" src="../bower_components/angular-aria/angular-aria.js"></script>
    <script type="text/javascript" src="../bower_components/angular-animate/angular-animate.js"></script>
    <script type="text/javascript" src="../bower_components/angular-material/angular-material.js"></script>

    <script type="text/javascript" src="scripts/index.js"></script>
    <script type="text/javascript" src="scripts/app/todoController.js"></script>
    <script type="text/javascript" src="scripts/app/config.js"></script>
    <script type="text/javascript" src="scripts/components/todoList/todoListDirective.js"></script>

</head>  
<body>

    ... check out source code ...

</body>  
</html>  

This is really no-brainer, just watch your loading order. AngularJS and Angular material are situated in bower_components folder, and other files are found in scripts folder.

I like to bootstrap Angular without ng-app directive since there can be cases that you need to prepare something prior to lunching application. But in this case, ng-app can be safely used as well.

index.js

For this application, file needs to handle only bootstrapping Angular, but you could also put this some bulk-require logic if you're into that rather than listing stuff in index.html. We wait for document loaded event so that Angular can be properly loaded and started.

function boot() {  
    angular.bootstrap(document, ['app'], {
        strictDi: true
    });
}

document.addEventListener('DOMContentLoaded', boot);  

In conclusion

We defined main entry point in package.json to be main.js. Then in main.js we specified to create new window which will have index.html as content. Once the fire is started, it will load index.js which handles bootstrapping AngularJS.

That's it? I though...

That's it for now. We'll build on that and add much more functionality. Some things to follow:

  • Building and packing application
  • Automatic updating
  • Data persistance
  • Project automatisation

Stay tuned!

Next, read how to add automatic updates.

About Vjekoslav Ratkajec

Software developer from Zagreb, Croatia. Love programming, running, hiking and biking. Adore nature and animals. Also author of this blog.

Comments