Cross-platform Desktop Application
Express Web Framework 

with NodeJS and AngularJS

Satit Rianpit

rianpit@gmail.com

6-10 July, 2015

Course outline

  • Node.js/io.js
  • node-webkit (nw.js)
  • ExpressJS
  • AngularJS
  • MySQL
  • Highcharts
  • Google Map
  • LumX

Node.js/io.js

Node.js is an open source, cross-platform runtime environment for server-side and networking applications written in JavaScript. Run on Windows, Linux, FreeBSD and OSX

Node.js Architecture

node-webkit

AngularJS

GulpJS

var gulp = require('gulp');
var coffee = require('gulp-coffee');
var jade = require('gulp-jade');

gulp.task('coffee', function () {
    gulp
        .src('coffee/**/*.coffee')
        .pipe(coffee())
        .pipe(gulp.dest('js'));
});

gulp.task('jade', function () {
    gulp
        .src('src/**/*.jade')
        .pipe(jade())
        .pipe(gulp.dest('app'));
});

gulp.task('default', ['jade', 'coffee']);

Gulp is a task runner which uses Node.js

Jade

doctype html
html(lang="en")
    head
        title "Hello world"
        script(type="text/script")
            if (foo) {
                bar(1 + 10)
            }

    body
        h1 Hello world

HTML template language

<!doctype html>
<html lang="en">
    <head>
        <title> "Hello world" </title>
        <script type="text/script">
            if (foo) {
                bar(1 + 10)
            }
        </script>
    </head>

    <body>
        <h1> Hello world </h1>
    </body>
</html>

hello.jade

hello.html

LumX

First front-end framework with material design for AngularJS

Bower

# bower init
# bower install jquery --save
# bower install lumx angular angular-route
# bower install bootstrap@3.3.2

KnexJS

SQL builder for JavaScript

knex('users').select('username', 'host', 'password').limit(10);

// Output:
SELECT username, host, password FROM users LIMIT 10;
knex('users').insert({
    username: 'hello',
    password: 'world',
    host: 'localhost'
});

// Output:
INSERT INTO users (username, password, host) 
VALUES ('hello', 'world', 'localhost');

Software installation

bower.json

package.json

{
  "name": "iBook",
  "version": "0.0.1",
  "description": "document management system",
  "main": "app/login/Login.html",
  "window": {
    "title": "iBook",
    "width": 1024,
    "height": 500,
    "toolbar": true,
    "frame": true,
    "position": "center",
    "icon": "icon.png"
  },
  "author": "Satit Rianpit",
  "license": "MIT",
  "devDependencies": {
    "gulp": "^3.8.11"
  },
  "dependencies": {
    "knex": "^0.7.6"
  }
}
{
  "name": "iBook",
  "version": "0.0.1",
  "authors": [
    "Satit Rianpit <siteslave@msn.com>"
  ],
  "description": "Description",
  "license": "MIT",
  "private": true,
  "dependencies": {
    "lumx": "~0.3.23"
  }
}

Command line

# bower init
? name: Test
? version: 0.0.1
? description: Hello world
? main file: app/login/Login.html
? what types of modules does this package expose?:
? keywords: nodejs, nodewebkit
? authors: Satit Rianpit <siteslave@msn.com>
? license: MIT
? homepage: http://github.com/siteslave
? set currently installed components as dependencies?: Yes
? add commonly ignored files to ignore list?: No
# npm init

name: (test) Test
version: (1.0.0)
description: nodejs
entry point: (index.js) app/login/Login.html
test command:
git repository: http://github.com/siteslave
keywords: nodejs
author: Satit Rianpit
license: (ISC) MIT

node-webkit/nwjs

<html>
    <head>
        <title>Hello world</title>
    </head>
    <body>
    <script>
        // https://nodejs.org/api/os.html
        var os = require('os');
        console.log(os.hostname());
        console.log(os.platform());
        console.log(os.arch());
    </script>
    <h1>Welcome you to world of JavaScript.</h1>
    </body>
</html>
{
  "name": "ngTutorial",
  "version": "0.0.0",
  "description": "Hello world app.",
  "main": "index.html",
  "window": {
    "title": "node-webkit demo",
    "toolbar": true,
    "frame": true,
    "width": 800,
    "height": 500,
    "position": "center"
  }
}

package.json

index.html

Runnig

# /path/to/nw.exe /path/to/app_folder

Node.js Packages

https://www.npmjs.com/

Jade

Jade - robust, elegent, feature rich template engine for Node.js

http://jade-lang.com

Basic Jade

# Tag
h1
div

# Attribute
div(ng-show="true")
button(type="text", disabled="true")
input(type="text", placeholder="Your name", size="20")

# Class
div.className
button(type="button").btn.btn--green.btn--l

# Id
div#idName
input(type="text", name="name")#txtName

# Script
script(src="app.js", type="text/script")
script
    if (a) console.log(a);
    else console.log(b);

# Css
link(href="style.css", rel="stylesheet")
style
    .btn { color: red; }
# Comment

// h1 Hello world
//- h1 Hello world

# Output
<!-- <h1>Hello world</h1> -->
<empty>

Jade Layout

doctype html
html(lang="en")
    head
        meta(charset="utf8")
        title Template
    body
        h1 I'm template
        
        block header
        block content
        block footer

    block scripts
extends ../layouts/Main

block header
    h1 I'm header
    hr
block content
    h2 I'm content.

block footer
    h3 I'm footer.

block scripts
    script(src="../app.js")

Main.jade

Index.jade

app
    - layouts
        |- Main.jade

    - pages
        |- Index.jade

    - app.js

folder structure

Demo

branch: ch01

AngularJS

Content in this section

  • Hello world.
  • Data binding
  • Controller & $scope
  • Directive
  • Filters
  • Factory
  • $http
  • Modules

Hello world app.

<html>
    <title>Hello world</title>
    <script src="path/to/angular.js"></script>

    <body ng-app>
        Your name: 
        <input type="text" ng-model="name" />
        <span>{{ name }}</span>
    </body>

</html>

Demo

branch: ch02

Data binding

<html ng-app ng-init="name='Satit'">

Your name: 
<span>{{ name }}</span>

<!-- use directive -->
<h1 ng-bind="name"></h1>

One-way data binding.

Your name: 
<input type="text" ng-model="name" />
<span>{{ name }}</span>

<!-- use directive -->
<h1 ng-bind="name"></h1>

Two-way data binding.

angular.controller('MainCtrl', function ($scope) {
    $scope.name = 'Satit Rianpit';
});

controller.js

app.html

Demo

branch: ch03

Controller & $scope

<script>
    angular.module('app', [])
        .controller('MainController', function ($scope) {
            //bind data to view
            $scope.name = 'Satit Rianpit';
            // bind to function
            $scope.showName = function () {
                alert($scope.name);
            };
        });
</script>

<body ng-app="app" ng-controller="MainController">
    Your name: 
    <input type="text" ng-model="name" />
    <button type="button" ng-click="showName()">Show me.</button>
</body>
var app = angular.module('app', []);

app.controller('MainController', function ($scope) { ... });

Or

<script src="MainController.js"></script>

Demo

branch: ch04

Directives

 

  • ng-show/ng-hide
  • ng-repeat
  • ng-if
  • custom directive

ng-show/ng-hide


<!-- App.jade -->
script(src="MainController.js")

button(type="button" ng-show="isShow", style="background-color: red") 
    | Welcome to AngularJS
 
button(type="button", ng-click="toggleMe()") Show/Hide
// MainController.js
app.controller('MainController', function ($scope) {
    $scope.isShow = true;

    $scope.toggleMe = function () {
        $scope.isShow = !$scope.isShow;
    };
});

Demo

branch: ch05

ng-repeat

input(type="text", ng-model="query")

ul
    li(ng-repeat="p in products | filter: query") 
        | {{ p.name }} [{{ p.qty }}]
angular.moduel('app', [])
    .controller('MainController', function ($scope) {
        $scope.products = [
            { name: 'Apple Watch', qty: 10 },
            { name: 'iPad', qty: 5 }
            { name: 'iPhone', qty: 15 },
            ...
        ];
    });

MainController.js

App.jade

Demo

branch: ch06

ng-if

ul
    li(ng-repeat="p in products") 
        span(ng-if="p.qty < 10", style="color: red;") {{ p.name }} [{{ p.qty }}]
        span(ng-if="p.qty >= 10", style="color: green;") {{ p.name }} [{{ p.qty }}]
angular.moduel('app', [])
    .controller('MainController', function ($scope) {
        $scope.products = [
            { name: 'Apple Watch', qty: 10 },
            { name: 'iPad', qty: 5 }
            { name: 'iPhone', qty: 15 },
            ...
        ];
    });

MainController.js

App.jade

Array objects.

Demo

branch: ch07

Custom directive

doctype html
html
    head
        title Directive
        script(src="../vendor/angular/angular.js")
        script(src="Directive.js")

    body(ng-app="app")
        hello(name="Satit Rianpit")
        
angular.module('app', [])
    .directive('hello', function () {
        return {
            restrict: 'E', // E = element, A = attribute, C = class
            template: '<div>Hello, {{ name }}</div>',
            scope: {
                name: '@'
            }
        };
    });

App.jade

Directive.js

Demo

branch: ch08

Filters

  • Build-in filter
  • Custom filter

Build-in filter

// script
$scope.price = 10000;
$scope.name = 'computer';

// jade
price: {{ price | number }} // result: 10,000
name: {{ name | uppercase }} // result: COMPUTER

https://docs.angularjs.org/api/ng/filter

Custom filter

// filter.js

app.filter('toSexName', function () {

    return function (sex) {
           return sex == '1' ? 'ชาย' : sex == '2' ? 'หญิง' : 'ไม่ทราบ';
    };

});


// page.html

เพศ: {{ sex | toSexName }}

Factory

app.factory('factoryName', function () {
        
    return {
        all: function () {
            // query database
            return rows;
        },
        search: function (query) {
            // query database
            return rows;
        }
    };

});

$http

app.factory('Api', function ($q, $http) {

        return {
            all: function () {
                   $http({ url: '/apis/all', method: 'post', data: { id: 1 }})
                        .success(function (data, status) {
                            // success
                        })
                        .error(function (data, status) {
                            // error
                        });
            }
        };

});

Routing

var app = angular.module('app', ['ngRoute']);

app.config(function ($routeProvider) {
        $routeProvider
             .when('/', {
                templateUrl: './main.html',
                controller: 'MainController'
            })
            .when('/add', {
                templateUrl: './add.html',
                controller: 'AddController'
            })
            .otherwise({ redirectTo: '/' });
    });

http://localhost:3000/index.html#/

http://localhost:3000/index.html#/add

LumX

  • Installation
  • Colors
  • Toolbar
  • Flex
  • Cards
  • Button
  • Icon
  • Datatable

Installation

# bower install lumx --save
<!-- Head -->
link(rel="stylesheet", href="vendor/lumx/dist/lumx.css")
link(rel="stylesheet", href="vendor/mdi/css/materialdesignicons.css")
link(rel="stylesheet", href="http://fonts.googleapis.com/css?family=Roboto:300,400,500,700")

<!-- Before body closing tag -->
script(src="vendor/jquery/dist/jquery.js")
script(src="vendor/velocity/velocity.js")
script(src="vendor/moment/min/moment-with-locales.js")
script(src="vendor/angular/angular.js")
script(src="vendor/lumx/dist/lumx.js")

Files including

Colors

Cross-platform Desktop Application

By Satit Rianpit

Cross-platform Desktop Application

  • 942