AngularJS training provides an overview of key AngularJS concepts and best practices for building Angular applications. The document introduces the trainer, Lauri Svan, and discusses AngularJS fundamentals like two-way data binding, dependency injection, templates, controllers and directives. It also outlines the typical structure of an Angular app, including modules, services and routing. Form validation, custom directives and asynchronous validation with ngModelOptions are also covered to demonstrate common Angular patterns and techniques.
2. Intro: About the Lecturer
● 15 year battle hardened veteran
● Head of Technology at SC5
● Helsinki Node.js co-founder
● In GitHub & Twitter
● “New school of engineering”
● Knows “why” & some “how” of
AngularJS
4. What is AngularJS
● Developed and maintained by Google
● Current version 1.5 (2.0 in Alpha)
● Good documentation and examples
● 3rd party libraries
● Insanely popular (see Bower, too)
● Easy to learn
● Get things done fast
● “Good enough”
6. Recipe for an Angular Application
App Logic:
● 1 Module (the app)
● 1-N Templates for each view
● 1-N Controllers for each view
● 1 Router to toggle between UI states
● 1-N Directives for widgets
● 0-N Resources for each REST API
endpoints
● 0-N Services for inter-app comms &
storing app state
What else?
● Style sheets for app visuals
● Hybrid packaging (optional)
7. Modules
// Create module without dependencies
angular.module(‘myModule’, [ ] );
// Module with dependency
var app = angular.module(‘myApp’, [ ‘myModule’ ] );
// Get module and define controller
var module = angular.module(‘myModule’);
module.controller( ‘myController’, function($scope) {
$scope.title = ‘myController’;
});
// Declare application in HTML
<div ng-app=”myApp”>
// Declare application to body in javascript
angular.bootstrap( document.body, [‘myApp’] );
9. Controllers
● Controllers allow to interact with a View and Model.
● Is where to hold your presentation logic.
● Controller purpose is to drive Model and View
changes.
● New instance is created for each invocation
10. Controllers + $scope
Context where the model is stored so that controllers, directives and
expressions can access it.
$scope is a clever Object which is automated bridge between Javascript and
DOM that holds synchronized data.
var app = angular.module(‘myApp’);
app.controller(‘myCtrl’, function( $scope ) {
$scope.title = “MyTitle”;
});
app.controller(‘MySubCtrl’, function( $scope ) {
$scope.content = “MyData”;
});
<div ng-controller=”myCtrl”>
<h1>{{ title }}</h1>
<div ng-controller=”MySubCtrl”>
<p>{{content }}</p>
<span>ref: {{ title }}</span>
</div>
<div>{{content }}</div>
</div>
11. ControllerAs
New way in 1.3, similar as will be in 2.0
Easier to identify which scope is variable belongs to.
var app = angular.module(‘myApp’);
app.controller(‘myCtrl’, function() {
this.title = “MyTitle”;
});
app.controller(‘MySubCtrl’, function() {
this.content = “MyData”;
});
<div ng-controller=”myCtrl as mainCtrl”>
<h1>{{ mainCtrl.title }}</h1>
<div ng-controller=”MySubCtrl as subCtrl”>
<p>{{ subCtrl.content }}</p>
<span>ref: {{ mainCtrl.title }}</span>
</div>
<div>{{ subCtrl.content }}</div>
</div>
12. $scope.$watch
Way to react View change in the controller
app.controller(‘myCtrl’, function($scope) {
this.value = ‘Initial value’;
var _this = this;
$scope.$watch(
// return variable to watch (reference)
function() {
return _this.value;
},
// Handler function
function( newValue, oldValue ) {
console.log( oldValue, ‘->’, newValue );
}
);
});
app.controller(‘myCtrl’, function($scope) {
$scope.value = ‘Initial value’;
$scope.$watch(
‘value’,
function( newValue, oldValue ) {
console.log( oldValue, ‘->’, newValue );
}
);
});
W
ithout ControllerAs (1.2.x)
13. Services
● Use to hold data that persist application lifecycle, as
controllers are discarded when they are removed
from view.
● All services are singletons.
● Controllers access services via dependency injection.
● Three ways of creating services: service, factory, provider
14. Service
Creates service which will be invoked with ‘new’ to create
instance. (singleton instance)
app.service( ‘MyService’, function() {
this.greet = function() { alert(‘Hello!’); };
this.getText = function() { return ‘Hello!’; };
});
app.controller(‘myCtrl’, function(MyService) {
this.text = MyService.getText();
this.sayHello = function() {
MyService.greet();
}
});
var ServiceClass = function() {
this.color = ‘green’;
}
ServiceClass.prototype.setColor = function(color) {
this.color = color;
}
app.service( ‘MyService’, ServiceClass );
app.controller(‘MyController’, function(MyService) {
this.color = MyService.color;
this.onClick= function(color) {
MyService.setColor(color);
}
});
15. Factory
Register service by returning service instance object.
Can take advantage of closures.
app.factory( ‘MyService’, function() {
var greetText = “Hello”;
return {
greet: function() { alert(greetText); },
setText: function(text) { greetText = text; }
};
});
// Probably most common way to use factory
app.factory(‘Articles’, function( $resource, Settings ) {
return $resource( Settings.ApiHost + ‘/api/article’ );
}
app.controller(‘myCtrl’, function(MyService) {
this.text = MyService.getText();
this.sayHello = function() {
MyService.greet();
}
});
16. Providers
Only service definition that can be passed to config()
function.
Use to customize service on configuration phase.
app.provider( ‘MyService’, function() {
this.host = ‘/’;
this.$get = function( $resource ) {
return $resource( this.host + ‘/api/myservice’ );
};
});
app.config( function( MyServiceProvider ) {
if( window.location.host !== ‘example.com‘ )
MyServiceProvider.host = ‘example.com‘;
});
app.controller(‘myCtrl’, function(MyService) {
this.data = MyService.get( {id: 1234} );
});
18. Filters
Filters are used for formatting data displayed to the
user.
Primarily used in expressions, but can be used in
controllers and services also.
{{ expression | filter1 | filter2 | ... }}
<span>{{ article.published | date:”yyyy-M-d” }}<span>
<span>{{ item.price | currency:”€” }}</span>
<label>{{ ‘ITEM_PRICE’ | translate }}</label>
<div ng-repeat=”person in persons | orderBy:’lastName’ | limitTo: 10”>{{ person.lastName}}</div>
// TIP: json filter is handy to check what object contains
<pre>{{ obj | json }}</pre>
19. Built-in filters
● currency - Format currency ( symbol, how many decimal numbers)
● number - To string, how many decimal numbers to use
● date - Format Date to string, use locale format as default
● json - Object to JSON string
● lowercase - Converts string to lowercase
● uppercase - Converts string to uppercase
● filter - select subset of array
● limitTo - creates new array with specified number of elements
● orderBy - Order array by the expression
21. Directives
A Directive can be anything, it can either provide powerful logic to an
existing specific element, or be an element itself and provide an injected
template with powerful logic inside.
Directives are markers on a DOM element (such as an attribute, element
name, comment or CSS class) that tell AngularJS's HTML compiler to attach
a specified behavior to that DOM element or even transform the DOM
element and its children.
Angular comes with a set of built-in directives:
ng-model, ng-repeat, ng-show/ng-hide, ng-if, ng-click, ng-disabled, ng-
mouseover, ng-blur, ng-src/ng-href, ng-class, ng-switch, ng-bind, ng-view ….
22. Custom directives 1
Directives can match attribute name, tag name,
comments or class name. Or restricted only to match
some of them
<my-dir></my-dir>
<span my-dir="exp"></span>
<!-- directive: my-dir exp -->
<span class="my-dir: exp;"></span>
Directives can emulate Shadow DOM behaviour with
option transclude
<my-element>
Hi there!
</my-element>
28. Forms
Form and controls provide validation services, so that
the user can be notified of invalid input.
This provides a better user experience, because the user
gets instant feedback on how to correct the error.
29. Forms
<form name=”myFrom” novalidate>
<label>Email:</label>
<input type=”email” name=”email” ng-model=”user.email” required />
<label>Password:</label>
<input type=”password” name=”password” ng-model=”user.password” required minlength=”8” />
<div ng-messages=”myForm.password.$error”>
<div ng-message=”required”>Password is required</div>
<div ng-message=”minlength”>Password is too short</div>
</div>
<button ng-disabled=”myForm.$invalid”>Submit</button>
</form>
30. Form CSS classes
● ng-valid: the model is valid
● ng-invalid: the model is invalid
● ng-valid-[key]: for each valid key added by $setValidity
● ng-invalid-[key]: for each invalid key added by $setValidity
● ng-pristine: the control hasn't been interacted with yet
● ng-dirty: the control has been interacted with
● ng-touched: the control has been blurred
● ng-untouched: the control hasn't been blurred
● ng-pending: any $asyncValidators are unfulfilled
31. Form CSS class example
<form name=”myFrom” novalidate>
<label>Email:</label>
<input
type=”email”
name=”email”
ng-model=”user.email”
required />
</form>
<style type="text/css">
form input.ng-invalid.ng-dirty {
outline-color: #FA787E;
}
</style>
32. Form validators
HTML5 input validators are built-in to Angular:
number, email, required, url, time, date, ..
Create own validators with directives:
<input name=”pwd”
type=”password
ng-model=”user.password”
required
minlength=”8”
validate-password-characters />
<div ng-messages=”myFrom.pwd.$error”>
<div ng-message=”required”>Password is required</div>
<div ng-message=”minlength”>Password is too short</div>
<div ng-message=”passwordCharacters”>Your password must contain a numeric, uppercase and ..
</div>
</div>
35. ngModelOptions
Validation and specially async validation may cause too
many calls for validation.
With ngModelOptions you can control when ngModel is
updated and validators are executed.
// Update when leaving input element
<input ng-model=”value” ng-model-options=”{ updateOn:’blur’ }” required />
// Update only when no changes in 500ms or immediately when leaving element
<input ng-model=”username” ng-model-options=”{ debounce: { default: 500, blur: 0 } }”
required validate-username-available />
36. Events
Angular scope have built-in event framework.
● $on - listen to event
● $emit - send event to upwards (self and parent
scopes)
● $broadcast - send event to downwards (self / child
scopes)
<div ng-controller="EventCtrl as parentCtrl" ng-scope>
<div ng-controller="EventCtrl as childCtrl1" ng-scope>
<div ng-controller="EventCtrl as subChildCtrl" ng-scope></div>
</div>
<div ng-controller="EventCtrl as childCtrl2" ng-scope>
</div>
</div>
$broadcast $send
37. Angular extension modules
● ngRoute - Routing and deeplinking
● ngResource - RESTful services
● ngAnimate - Support for JS, CSS transitions and
animations hooks
● ngSanitize - Bind HTML content safe way
● ngTouch - Touch events
● ngMessages - Enhanced support to show messages
38. ngRoute
To create routing for your Angular application include
ngRoute module and defined routes in config()-function.
angular.module(´myApp´, [´ngRoute´]).config(
function( $routeProvider, $locationProvider ) {
$routeProvider
.when('/', {
templateUrl: 'main.html',
controller: ´mainController´
}).
.when('/page1', {
templateUrl: page1.html',
controller: ´page1Controller´
}).
.otherwise({ redirectTo: ´/´ });
$locationProvider.html5Mode(true);
});
index.html:
<body>
<div ng-view> Route content will be here </div>
main.html:
<h1>main page</h1>
<a href=”/page”>goto to sub page</a>
page.html:
<h1>Page1 </h1>
<a href=”/”>back to main page</a>
40. ngResource
Factory service which creates a resource object that lets
you to interact RESTful API.
Makes data handling object oriented.
var User = $resource(
‘/api/user/:id’,
{ id: ‘@_id’ },
{
update: { method: ‘PUT’ }
});
var person = new User({
firstName: ‘John’,
lastName:’doe’
});
person.$save();
person.lastName = ‘Doe’;
person.$update();
var person = new User({
firstName: ‘John’,
lastName:’doe’
});
person.$save(); // POST: ‘/api/user’
person.lastName = ‘Doe’;
person.$update(); // PUT: ‘/api/user/1’
// GET: ’/api/user?firstName=John’
var users = User.query({ firstName: ‘John });
var john = User.get({ id: 1234 }, function() {
john.lastLogin = new Date();
john.$update();
});
43. ngAnimate
Adds animation hooks for common directives such as
ngRepeat, ngView and ngShow.
Also pays attention to CSS class changes with ngClass by
triggering add and remove hooks.
When change is triggered it places state CSS class, like
ng-hide, and end state ng-hide-active. And after
animation is ended it removes those classes
46. Testing
AngularJS is designed that applications are testable.
Dependency Injection makes testing easier, by allowing
inject mock instead of real module.
47. Unit testing with Karma
my-ctrl.js:
angular.module('myApp',[])
.controller('myCtrl', function( $http ) {
var _this = this;
$http.get('/api/data').success(function(data) {
_this.data = data;
});
this.isOk = function() {
return this.data && this.data.ok;
}
});
my-ctrl.spec.js:
describe('controller:myCtrl', function() {
beforeEach( module('myApp') );
it('should fetch data from server and return ok',
inject(function($controller, $httpBackend) {
$httpBackend
.when('GET', '/api/data')
.respond({ ok: true });
$httpBackend.expectGET('/api/data');
var ctrl = $controller( 'myCtrl' );
expect(ctrl.isOk()).toBe(false);
$httpBackend.flush();
expect(ctrl.isOk()).toBe(true);
})
);
});
48. Dependency Injection in testing
it('should fetch data from server and return ok', inject(function($controller) {
var ctrlCB;
var myHttpMock = {
get: function() {
return {
success: function(cb) { ctrlCB= cb; }
};
}
}
var ctrl = $controller( 'myCtrl', { $http: myHttpMock } );
expect(ctrlCB).not.toBe(undefined);
cb( { ok: true } );
expect(ctrl.isOk()).toBe( true );
}));
49. End-to-end testing with protractor
describe('password view', function() {
it('should show error when too short input', function() {
browser.get('http://localhost:63342/angular-training/protractor/index.html');
element(by.model('user.password')).sendKeys('test');
var messages = element(by.id('password.error'));
expect(messages.getText()).toContain('short');
element(by.model('user.password')).sendKeys('test12345ABC-');
element(by.buttonText(‘save’)).click();
});
});
50. Best practices
● Design UI/HTML first!
Create HTML first and then just add functionality with
Angular. Style guide + UI mock-ups
● Avoid using $scope directly
By eliminating usage of $scope, code is closer to 2.0
style
● Avoid using ng-controller in HTML
Use through route or directives, do not add them
directly.
● Testing is easy!
Write tests for your code / site
51. Best practices
● If repeating elements in HTML, create directive for them
● Create services and use $resource to access server APIs
● Do not format data in the controllers, which will be displayed in the
view, instead use filter. Example, localisation, date/time, currency, etc.
Create filters that do it for you, and you can then modify those filters
and reflect changes to whole site.
● Avoid long lists which contains lots of bind data, that can cause
performance issues. Use paging to limit elements, if data changes in
page, otherwise use one-time binding (Angular 1.3), or libraries like
‘bindonce’ for Angular 1.2
● If you are binding without dot, you are probably doing something
wrong. {{ name }} = BAD, {{ user.name }} = GOOD
● Keep code structured
52. Caveats
● 2000 watches is considered as saturation point, after that page
rendering may seem slow
● Use directive isolated scope only when needed. Specially with
transclude, it can cause problems not to be able to access variables
● Namespace
Modules does not add namespace for functions. Plan function naming
(controller/service/directive/filter)
● Dependency Injection and javascript minify
DI breaks when minified. Declare in array syntax or use
ngAnnote/ngMin
● When using 3rd party libraries etc, remember to call $apply to get
changes render to page
53. Tools & Utilities for AngularJS
Boilerplates
https://github.com/SC5/gulp-bobrsass-boilerplate/tree/angularjs
https://github.com/DaftMonk/generator-angular-fullstack
Testing:
http://angular.github.io/protractor/#/
http://karma-runner.github.io/0.12/index.html
http://www.ng-newsletter.com/advent2013/#!/day/19
Build and minification:
https://github.com/olov/ng-annotate
54. More about AngularJS
Community in Helsinki capital area
https://www.facebook.com/groups/helsinkijs/
http://frontend.fi/
AngularJS Primer
https://www.airpair.com/angularjs/posts/angularjs-tutorial
https://thinkster.io/angulartutorial/a-better-way-to-learn-angularjs/
http://lostechies.com/gabrielschenker/2013/12/05/angularjspart-1/
Blogs that have good information about AngularJS:
http://www.yearofmoo.com/
http://www.jvandemo.com/
Good reads:
http://sc5.io/posts/how-to-implement-loaders-for-an-angularjs-app
http://teropa.info/blog/2014/11/01/why-i-think-angular-2-will-still-be-angular.html
56. Test setup
● Install Node.js for test server
http://nodejs.org/download/
● Download and extract training examples
https://docs.google.com/a/sc5.io/uc?
authuser=0&id=0B_18Pna_ughFNWVZaUV1amV6bjA&export=download
● Go to exercises folder and execute commands
> npm install
> npm start
● Open local web server with browser
http://localhost:3000/