Rainer Stropek: Advanced Developer Conference 2013
Rainer Stropek: Advanced Developer Conference 2013
Rainer Stropek
software architects gmbh
Web http://www.timecockpit.com
Mail [email protected]
Twitter @rstropek
Agenda
Introduction
Whats it all about?
Image Source:
http://flic.kr/p/9bUJEX
Learn
Angular by example
Image Source:
http://flic.kr/p/3budHy
How far?
Image Source:
http://flic.kr/p/765iZj
Stop or go?
Critical evaluation
Image Source:
http://flic.kr/p/973C1u
TypeScript
TypeScript advantages
TypeScript disadvantages
Introduction
Whats it all about?
Image Source:
http://flic.kr/p/9bUJEX
Whats AngularJS
Developers Perspective
MVC
Dependency
injection system
Handles
Whats AngularJS
Developers Perspective
Navigation
HTML
extensibility mechanism
Custom directives
MVC
View
Model
Layers
HTML
CSS
Controller
Workflow
JavaScript
User
Architectural Pattern
API
Server
Data Binding
MVC Notes
MVW
Clear
Enables
Test business logic and UI behavior (also kind of logic) without automated UI tests
Important Differences
Plugin-free
Extensibility introduced by AngularJS
JavaScript
Many different development
environments
Open Source
Shared Code
JavaScript/TypeScript Everywhere
Client
Data Model
Logic
Server
Data Model
Logic
angular.module('helloWorldApp', [])
.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'MainCtrl'
})
.when('/about', {
templateUrl: 'views/about.html',
controller: 'AboutCtrl'
})
.otherwise({
redirectTo: '/'
});
});
angular.module('helloWorldApp')
.controller('MainCtrl', function ($scope) {
});
<div class="container"
ng-view="">
</div>
<div class="hero-unit">
<h1>'Allo, 'Allo!</h1>
</div>
SPA
Tools
Yoeman
angular-seed
Bower for web package management
Build
JetBrains WebStorm
Not free
Windows, Mac, Linux
Specialized on web apps
Good integration of external tools
Project setup
UI
Server-side
Demo
Sublime text
Learn
Angular by example
Image Source:
http://flic.kr/p/3budHy
Project Setup
In Visual Studio
Demo
TypeScript
NuGet
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Angular.js Samples Using TypeScript</title>
<link href="../../../Content/bootstrap/bootstrap.css" rel="stylesheet">
<link href="helloWorldWithController.css" rel="stylesheet">
<script src="../../../Scripts/angular.js"></script>
<script src="helloWorldWithController.js"></script>
</head>
<body ng-app>
<div ng-controller="HelloCtrl">
<form>
<h2>Two-Way Binding</h2>
<label for="messageInput">Say 'Hello' to:</label>
<input type="text" id="messageInput" ng-model="name">
<h2>Simple Bindings</h2>
<table class="table table-hover table-condensed">
<tr>
<th>Syntax</th><th>Result</th>
</tr>
<tr>
<td>Interpolation</td><td>Hello, {{name}}!</td>
</tr>
<tr>
<td>ng-bind</td><td>Hello, <span ng-bind="name" />!</td>
</tr>
<tr>
<td>Interpolation with controller function</td>
<td>Hello, {{getName()}}!</td>
</tr>
<tr>
<td>ng-bind with getEnclosedName</td>
<td>Hello, <span ng-bind="getEnclosedName('b')" />!</td>
</tr>
<tr>
<td>ng-bind-html-unsafe with getEnclosedName</td>
<td>Hello, <span ng-bind-html-unsafe="getEnclosedName('b')" />!</td>
</tr>
</table>
</form>
</div>
</body>
</html>
Controller
/// <reference
path="../../../tsDeclarations/angularjs/angular.d.ts"/>
// Create a custom scope based on angular's scope and define
// type-safe members which we will add in the controller function.
interface IHelloWorldScope extends ng.IScope {
name: string;
getName: () => string;
getEnclosedName: (tag: string) => string;
}
Referred to from
ng-controller
Controller
Collections
Binding to Collections
Create collection in
controller
Binding the view to
collections
Demo
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body ng-app>
<div ng-controller="HelloCtrl">
<form>
<h2>Collection Binding</h2>
<table class="table table-hover table-condensed">
<tr>
<th>Pos.</th>
<th>ISO Code</th>
<th>Country Name</th>
</tr>
<tr ng-repeat="country in countries">
<td>{{$index}}</td>
<td>{{country.isoCode}}</td>
<td>{{country.name}}</td>
</tr>
</table>
</form>
</div>
</body>
</html>
Controller
/// <reference
path="../../../tsDeclarations/angularjs/angular.d.ts"/>
// Create a custom scope based on angular's scope and define
// type-safe members which we will add in the controller function.
interface IHelloWorldScope extends ng.IScope {
name: string;
countries: ICountryInfo[];
getName: () => string;
getEnclosedName: (tag: string) => string;
}
interface ICountryInfo {
isoCode: string;
name: string;
}
var HelloCtrl = function
$scope.countries = [
{ isoCode: 'AT',
{ isoCode: 'DE',
{ isoCode: 'CH',
};
($scope: IHelloWorldScope) {
name: 'Austria' },
name: 'Germany' },
name: 'Switzerland' }];
Controller
Scopes
Hierarchy of Scopes
Demo
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Angular.js Samples Using TypeScript</title>
<link href="../../../Content/bootstrap/bootstrap.css" rel="stylesheet">
<script src="../../../Scripts/angular.js"></script>
<script src="hierarchyOfScopes.js"></script>
</head>
<body ng-app>
<div ng-controller="WorldCtrl" class="container">
<hr>
<ul>
<li ng-repeat="country in countries">
{{country.name}} has population
of {{country.population | number:1}} millions,
{{worldsPercentage(country.population) | number:1}} %
of the World's population
</li>
</ul>
<hr>
World's population: {{population | number:1}} millions
</div>
</body>
</html>
Controller
/// <reference
path="../../../tsDeclarations/angularjs/angular.d.ts"/>
interface ICountry {
name: string;
population: number;
}
Controller
Batarang
Chrome Addin
<body ng-app="notificationsApp" ng-controller="NotificationsCtrl">
</body>
module NotificationsModule {
export class NotificationsCtrl {
constructor(
private $scope: INotificationsCtrlScope,
private notificationService: NotificationsService) { }
}
export class NotificationsService {
}
angular.module("notificationsApp", )
.constant("MAX_LEN", 10)
.value("greeting", "Hello World!")
.controller("NotificationsCtrl",
NotificationsModule.NotificationsCtrl)
.factory("notificationService",
NotificationsModule.NotificationsService.Factory);
Modules, Services
Dependency Injection
Predefined services
Dependency Injection
Modules, Services
Dependency Injection
Demo
module NotificationsModule {
export interface INotificationsArchive {
archive(notification: string);
getArchived(): string[];
}
}
Notification Service
Contract
constructor() {
this.archivedNotifications = [];
}
archive(notification: string) {
this.archivedNotifications.push(notification);
}
public getArchived(): string[]{
return this.archivedNotifications;
}
}
}
Notification Service
Archive Implementation
Notification Service
Service Implementation
Notification Service
Controller
/// <reference
path="../../../tsDeclarations/angularjs/angular.d.ts"/>
/// <reference path="NotificationsArchive.ts"/>
/// <reference path="NotificationsService.ts"/>
/// <reference path="NotificationsCtrl.ts"/>
angular.module("notificationsApp", ["notificationsArchive"])
.value("greeting", "Hello World")
.constant("MAX_LEN", 10)
.controller(
"NotificationsCtrl",
NotificationsModule.NotificationsCtrl)
.factory(
"notificationService",
NotificationsModule.NotificationsService.Factory);
Notification Service
Dependency Injection
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Angular.js Samples Using TypeScript</title>
<link href="../../../Content/bootstrap/bootstrap.css" rel="stylesheet">
<script src="../../../Scripts/angular.js"></script>
<script src="NotificationsArchive.js"></script>
<script src="NotificationsService.js"></script>
<script src="NotificationsCtrl.js"></script>
</head>
<body ng-app="notificationsApp" ng-controller="NotificationsCtrl">
<div style="margin: 10px">
<form role="form">
<textarea ng-model="notification" cols="40"
rows="3" class="span6"></textarea><br>
<button class="btn btn-primary"
ng-click="vm.addNotification()">Add</button>
</form>
</div>
<table class="table table-striped table-bordered">
<tr>
<th>Notifications</th>
</tr>
<tr ng-repeat="notification in vm.getNotifications()">
<td>{{notification}}</td>
</tr>
</table>
</body>
</html>
Notification Service
View
Server Communication
$http
service (ng.IHttpService)
$resource
$q
$httpBackend
service (ng.IHttpBackendService)
$http
Server Communication
Demo
Cloud Backend
Azure Mobile Services
Create a table
Step 1: No protection
Step 2: Protection with API key
/// <reference
path="../../../tsDeclarations/angularjs/angular.d.ts"/>
module MobileServicesDataAccess {
export interface ITableRow {
id?: number;
}
Access Class
REST Access Layer
}
public
public
public
public
public
Access Class
REST Access Layer
Access Class
REST Access Layer
Unit Tests
REST Access Layer
...
it(' should issue a POST to Azure Mobile Service for insert', () => {
$httpBackend.expectPOST("https://dummyService.azure-mobile.net
/tables/dummyTable")
.respond(201 /* Created */);
var data: IDummyRow = {};
table.insert(data);
$httpBackend.flush();
});
...
afterEach(() => {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
});
Unit Tests
REST Access Layer
How Far?
Image Source:
http://flic.kr/p/765iZj
angular.module('MyReverseModule', [])
.filter('reverse', function() {
return function(input, uppercase) {
var out = "";
for (var i = 0; i < input.length; i++) {
out = input.charAt(i) + out;
}
// conditional based on optional argument
if (uppercase) {
out = out.toUpperCase();
}
return out;
}
});
function Ctrl($scope) {
$scope.greeting = 'hello';
}
<body>
<div ng-controller="Ctrl">
<input ng-model="greeting" type="greeting"><br>
No filter: {{greeting}}<br>
Reverse: {{greeting|reverse}}<br>
Reverse + uppercase: {{greeting|reverse:true}}<br>
</div>
</body>
Filters
Formatting filters
currency
date
json
lowercase
number
uppercase
Array-transforming filters
filter
limitTo
orderBy
Advanced $http
Interceptors
Support
For
for JSONP
myModule.directive('button', function() {
return {
restrict: 'E',
compile: function(element, attributes) {
element.addClass('btn');
if (attributes.type === 'submit') {
element.addClass('btn-primary');
}
if (attributes.size) {
element.addClass('btn-' + attributes.size);
}
}
}
}
Directives
Localization
Internationalization
(i18n)
Abstracting strings and other locale-specific bits (such as date or currency formats) out of
the application
Localization
(L10n)
For
Recommended
Book
Kozlowski, Pawel; Darwin, Peter Bacon: Mastering Web Application Development with
AngularJS
Sample
http://bit.ly/AngularTypeScript
Stop or Go?
Critical Evaluation
Image Source:
http://flic.kr/p/973C1u
Stop or Go?
Many
You
Operating systems
Browsers
Learning
Stop or Go?
TypeScript
for productivity
Clear
Testability
Possible code reuse between server and client
One
Relatively
AngularJS by Google
Rainer Stropek
software architects gmbh
Q&A
Mail [email protected]
Web http://www.timecockpit.com
Twitter @rstropek
Try
for free and without any risk. You can get your trial account
at http://www.timecockpit.com. After the trial period you can use
for only 0,20 per user and month without a minimal subscription time and
without a minimal number of users.