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