A complete crash course with 7 pratical labs, to have a head start developing single page applications with Angular. It also contains advanced topics, like Transclusion, Directive to directive communication and UI Router.
High Quality presentation: https://goo.gl/3OwQXf
Download Labs: https://goo.gl/cVI6De
2. Summary
● What is AngularJS
○ The Web before AngularJS
○ Traditional Web Applications, SPAs
● How an AngularJS app is made
○ Modules, Controllers, Directives
○ Services, Providers, Factories
● Let’s build something
○ Angular Lab: build your own blog
● Advanced topics
○ Routing, custom directives, Transclusion, Directive-
to-Directive Communication
6. ● Several OSs (Win, MacOSX, Linux, Mobile)
● Mobile devices are performant
● HTML5, CSS3, SVG give a better UX
● Write once, run everywhere
The concept of app is evolving...
● Website user interfaces are becoming like
standalone applications
● Fast loading of server-side data
so...
7. Single Page Application (SPA)
Client Server
GET /
GET /api/blog/posts
[{ "id": 123, "title": "Hello!" },
{ "id": 125, "title": "Bye!" }]
9. What is AngularJS?
● A structural framework for dynamic web apps
● A solution for creating SPA (One Page Application)
● MVC done right (separation of application logic, data
models and views)
● A new way to enrich HTML, turning it in a declarative
language
● Data models are plain Javascript objects
● Context aware communication
● Dependency Injection (Increased testability)
15. Module
You can think of a module as a container for the different
parts of your app – controllers, services, filters, directives,
etc.
angular.module("fooLib", []);
var myApp = angular.module("myApp", ["fooLib"]);
In Java this concept is close to packages
16. Controller
● Business logic for user interaction
● Model-View wiring code
angular.module("myApp", [])
.controller("MainCtrl", function($scope) {
$scope.name = "John Doe";
$scope.countChars = function(text) {
return text.length;
}
});
18. Service/Provider/Factory
● Lazy-loaded Singleton object
● Provide a method to keep data around for
the lifetime of the app
● Communicate across controllers in a
consistent manner
angular.module("myApp", [])
.factory("UserService", function($http) {
var _currUser;
return {
getCurrentUser: function() { return _currUser; },
setCurrentUser: function(user) { _currUser = user; }
}
});
20. Setup Labs Environment
1. download labs here: https://goo.gl/cVI6De
2. open the workshop directory in Intellij IDEA
3. open the terminal (bottom left)
4. npm install
5. npm start
21. http://jsbin.com/mejeno/edit
● Declarative HTML
● Automatic data binding
(two-way data binding)
● Easy composability
● Application state
organized in scopes
● IDs everywhere
● Low level DOM events
management
● Mixed UI and
behavioural logic
● Require knowledge of
the entire DOM structure
< ng-lab="0" />
22. You will surely write less code!
● Registering callbacks
● Manipulating HTML DOM programmatically
● Marshalling data to and from the UI
● Writing tons of initialization code just to get
started
● Registering callbacks
● Manipulating HTML DOM programmatically
● Marshalling data to and from the UI
● Writing tons of initialization code just to get
started
23. The magic of two-way data binding
● In classic web frameworks (no javascript),
view reflects the model at render time.
Template
HTML
Model
template.render(model)
View
HTML
Model
snapshot
24. The magic of two-way data binding
● In AngularJS the template is compiled into a
reactive view, bindable to a changing model
View
HTML
Reactive
components
linkFn = $compile(template)
Model
linkFn($scope)
Template
HTML with
directives
25. Scope
● Source of truth for the application state
● The glue between application controller and
the view
● Follows a hierarchical structure
● Can propagate events and monitor watch
expressions
28. Scope Events
● Watch on scope changes
● Publish - Subscribe paradigm
● Powerful to keep components decoupled
$watch $broadcast $emit $on
Register to an
expression on
the model
Publish from
parent to
children
Publish from
child to parents
Subscribe to
incoming events
29. Scope Events - $watch
var
fooBar; $scope
$scope
$scope.$watch("fooBar",
function(newValue, oldValue) {
console.log(newValue)
});
View
Enter fooBar:
My foobar
30. $watch out for {{ }}
● Every time there is a change on the $scope,
expressions on it and its children are evaluated and the
result, if changed, reflected into the DOM
● Dangerous for long tables rendering (thousands of
watches)
One-time binding to the rescue!
<div>{{ ::person.firstName }}</div>
31. Scope Events - $broadcast
$scope
$scope $scope
$scope
$scope.$on("fooBar",
function(evt, msg) {
console.log(msg);
});
$scope.$broadcast("fooBar",
"This is an important
message!");
32. Scope Events - $emit
$scope
$scope $scope
$scope
$scope.$on("fooBar",
function(evt, msg) {
console.log(msg);
});
$scope.$emit("fooBar",
"This is an important
message!");
$scope.$on("fooBar",
function(evt, msg) {
console.log(msg);
});
33. Who can create scopes?
Controllers
● Using ng-controller
● Scopes can only be
child scopes
(prototypical inheritance)
Directives
● With a specific
configuration, when they
are included in the
HTML
● Scopes can be both
child or isolated
34. Built-in Directives
All the ng- directives come from the core library:
● ng-show or ng-hide: show or hide a component
● ng-if: adds or removes a component from the DOM
● ng-switch: allocates or deallocates a component on the
DOM based on a switch-case logic
● ng-click: runs an expression when clicking on a
component
● ng-repeat: iterates an array and repeat a component
● ng-model: binds a form component to a scope property
● ng-class: conditionally adds or removes CSS classes
35. Expressions
● Used all over AngularJS apps
● Executed in the current $scope context and have
access to $scope properties
● They don’t throw errors if it’s TypeError or
ReferenceError
● They don’t allow for any control flow functions (e.g.,
if/else)
● They can accept a filter and/or filter chains
<div>{{ person.firstName }}</div>
<div>{{ 5 * 2 + 10 }}</div>
<div><input type="text" ng-model="num" />
<div ng-show="num > 10">Can you see me?</div>
36. Directive ng-repeat
● Iterates over a collection and instantiates a
new template for each item in the collection.
● Each item in the collection is given its own
template and therefore its own scope.
<ul ng-controller="PeopleController">
<li ng-repeat="person in people">
{{person.name}} lives in {{person.city}}
</li>
</ul>
37. < ng-lab="1" />
● Refactor the blog page example
● Iterate over posts array on the current
$scope
● Toggle comments box
● Enable the user to remove blog posts by
clicking on the specific link
38. Filters
● Provide a way to format the data we display
to the user
● Angular gives us several built-in filters as
well as an easy way to create our own
● Filters can be used in views, controllers and
services
39. Usage Syntax in HTML templates
{{ name | uppercase }}
● Without params
{{ 123.4567890 | number: 2 }}
{{ user.birthday | date: 'short' }}
{{ posts | filter: 'animal' }}
● With params
JOHN DOE
123.46
7/23/15 9:59 PM
[list filtered by object containing “animal”]
40. Usage Syntax in controllers/services
$filter("uppercase")(name);
● Without params
JOHN DOE
$filter("number")(123.4567890, 2);
$filter("date")(user.birthday, "short");
$filter("filter")(posts, "animal");
● With params
123.46
7/23/15 9:59 PM
[list filtered by object containing “animal”]
41. < ng-lab="2" />
● Add date filter to each blog post
● Enable filtering blog posts by freetext
42. Service, Provider and Factory
● Shared components
● Not related to presentation layer
(only access to $rootScope)
● Singleton components
● Lazy-loaded when injected the first time
43. Service
● Syntax:
angular.module("myApp", [])
.service("MyService", function MyServiceImpl() {
this.hello = function() {
return "Hello World";
};
});
● Result:
new MyServiceImpl() is called and returned
● Usage:
Can be useful for sharing utility functions to invoke by simply appending ()
to the injected function reference.
44. Factory
● Syntax:
angular.module("myApp", [])
.factory("MyService", function MyServiceImpl() {
var privateStuff = "";
return {
hello: function() { return "Hello World"; }
};
});
● Result:
The value returned by invoking MyServiceImpl()
● Usage:
Can be useful for returning a “class” function that can then be new'ed to
create instances.
45. Provider
● Syntax:
angular.module("myApp", [])
.provider("MyService", function() {
var _key;
return {
setApiKey: function(key) { _key = key; }
$get: function() {
return {
function() { return "Hello World " + _key; }
}
}
};
});
● Result:
The value returned by invoking $get()
● Usage:
Can be useful when you need to configure your service before using it (e.
g.: setting an ApiKey or a baseUrl)
46. Config
● Allows to configure Providers before the app
is bootstrapped
● Useful for setting API keys, view routes
In Java this concept is close to property files
49. Going back to the controller definition...
angular.module("myApp", [])
.controller("MainCtrl",
function($scope, FooService) {
$scope.name = "John Doe";
$scope.countChars = function(text) {
return FooService.countStringLength(text);
}
});
angular.module("myApp", [])
.controller("MainCtrl",
["$scope", "FooService", function($scope, FooService) {
$scope.name = "John Doe";
$scope.countChars = function(text) {
return FooService.countStringLength(text);
}
}]); That notation is used to keep injection working when compressing the final javascript
artifact using, for example, requirejs r.js compiler (with uglify).
50. Promises
● Problem:
○ callback “pyramid of Doom”
step1(function (value1) {
step2(value1, function(value2) {
step3(value2, function(value3) {
step4(value3, function(value4) {
// Do something with value4
});
});
});
});
51. Angular $q service to the rescue!
● Let’s flatten the pyramid:
promisedStep1
.then(promisedStep2)
.then(promisedStep3)
.then(promisedStep4)
.then(function (value4) {
// Do something with value4
})
.catch(function (error) {
// Handle any error from all above steps
})
.finally(function (error) {
// Handle finally from all above steps
});
52. Parallel requests
var firstRequest = $http.get("/first.html");
var secondRequest = $http.get("/second.html");
// Wait for all
$q.all([firstRequest, secondRequest])
.then(function(results) {
// Do something with both results
})
.catch(function (error) {
// Handle any error from all above steps
})
.finally(function (error) {
// Handle finally from all above steps
});
53. Deferred objects
var getBlogPosts = function() {
var deferred = $q.defer();
$timeout(function() {
deferred.resolve([{"title": "a blog post!"}];
}, 5000);
return deferred.promise;
};
Can resolve or reject their promises
● Usage:
Could be useful when you want to convert a callback-paradigm into a
Promise philosophy!
54. Angular $http service
// Simple GET request example:
$http.get('/someUrl')
.success(function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
})
.error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
● Reflects HTTP request methods:
○ GET, POST, PUT, DELETE, HEAD
● Returns a promise with 2 extra methods:
55. < ng-lab="3" />
● Remove $scope.posts from MainController
● Implement $http methods in BlogApi service
● Load posts from BlogApi.getPosts();
● Wire removePost() to BlogApi.removePost();
56. Multi screen navigation
● Problem:
○ Multi-screen single web application
○ Complex tabs, navigation
○ History management (back button)
○ Query params
59. How to navigate
<a ui-sref="home">Go Home</a>
<a ui-sref="viewBlogPost({ id: post.id })">Show More…</a>
HTML side:
Code side:
angular.module("myApp", [])
.controller("MainCtrl", function($scope, $state) {
$scope.goToBlogPost = function(id) {
$state.go("viewBlogPost", { id: id });
};
});
60. < ng-lab="4" />
● Move Blog Post list template into a separate
HTML fragment
● Create routes for home and addPost
● Add ui-sref to navigation bar for addPost
61. Forms in Angular
● Controls (input, select,
textarea) are ways for a
user to enter data
● A Form is a collection of
controls for the purpose
of grouping related
controls together.
● Angular provides
validation services, the
user can be notified of
invalid input before
submitting a form.
62. Directive ng-model
● Binds an input to the current $scope
● Applies validation behaviours
● Registers itself with the parent form
● Works with input, select, textarea
<input type="text" ng-model="person.name" />
<input type="email" ng-model="person.email" />
<input type="number" ng-model="person.age" min="1" />
<textarea ng-model="person.bio" ng-required="true"></textarea>
63. Validation in forms
● ng-model retains an internal state:
○ $touched/$untouched
○ $pristine/$dirty
○ $valid/$invalid
○ $error
● It propagates its state to the parent form:
○ $pristine/$dirty
○ $valid/$invalid
○ $error
65. < ng-lab="5" />
● Create form for adding a new blog post
● Ensure validation on all fields
● Call BlogApi.addPost(newPost);
● Redirect to the home page ($state.go());
67. ● restrict
○ defines when the directive could be injected:
Attribute
A
CSS
Class
C
Element
E
68. ● restrict
○ defines when the directive could be injected:
Attribute
A
<div
blog-post="data"
button-label="Show more..."
can-remove="user.isAdmin()">
</div>
69. ● restrict
○ defines when the directive could be injected:
Element
E
<blog-post
content="data"
button-label="Show more..."
can-remove="user.isAdmin()">
</blog-post>
70. ● restrict
○ defines when the directive could be injected:
CSS
Class
C
<div class="blog-post"
content="data"
button-label="Show more..."
can-remove="user.isAdmin()">
</div>
71. ● templateUrl
○ Url of the file containing an HTML fragment
representing the directive template
○ It can be a function returning an Url
● template
○ A string containing an HTML fragment representing
the directive template
○ It can be a function returning an Url
<div>
<h1>{{title}}</h1>
<p>{{text}}</p>
</div> The template must have exactly one
root element!
72. ● scope
○ false (default): it doesn’t create a new scope
○ true: it creates a new child scope
○ {}: it creates a new isolated scope
scope: {
buttonLabel: "@"
content: "=",
canRemove: "&"
}
<blog-post
button-label="Show more..."
content="post.data"
can-remove="user.isAdmin()">
</blog-post>
@ = &
one-way binding of a
string
two-way binding
between scopes
expression evaluation on
parent scope
73. < ng-lab="6" />
● Refactor the main page wrapping each blog
post into a directive
● Use isolate scope to pass data into the new
directive
74. Transclusion
Nesting of HTML content (also directives)
inside a directive
This mechanism allows you to grab the content of the DOM element of your
directive and include it anywhere in the directive's template.
Tabs Accordion
75. Transclusion
How to start using it the “easy” way
1. Directive definition
angular.module("myApp", [])
.directive("movieCard", function() {
return {
transclude: true,
scope: {
title: "@"
},
templateUrl: "partials/movie-card.html",
controller: function($scope, $element) {},
link: function(scope, elem, attrs, ctrl) {}
};
});
76. Transclusion
How to start using it the “easy” way
2. Directive template (injection point)
<div>
<h1>{{title}}</h1>
<div ng-transclude></div>
</div>
77. Directive-to-Directive communication
How to create a DSL in Angular
Tabs
<tabs>
<tab title="Tab 1">
<div><input placeholder="Say something…"/></div>
<div><button>Post Comment</button>
</tab>
[...]
</tabs>
78. Directive-to-Directive communication
How to create a DSL in Angular
Accordion
<accordion>
<accordion-section title="Section 1">
<div>Quis nostrud exercitation ullamco…</div>
</accordion-section>
[...]
</accordion>
79. 1. Child directive definition example
angular.module("myApp", [])
.directive("tab", function() {
return {
require: "^tabs",
transclude: "true",
templateUrl: "partials/tab.html",
scope: {
title: "@"
},
link: function(scope, elem, attrs, tabsCtrl) {
tabsCtrl.registerTab(scope);
}
};
});
Directive-to-Directive communication
How to create a DSL in Angular
80. How to use require in directives
Directive-to-Directive communication
How to create a DSL in Angular
fooBar ?fooBar ^fooBar ?^fooBar
Require fooBar
on same element
and pass it to
linking function
Pass fooBar
controller if
available on
same element to
linking function. If
not, pass null.
Require fooBar
on one of the
parent elements
and pass it to
linking function
Pass
someDirective
controller if
available on one
of parent
elements to
linking function. If
not, pass null
81. 2. Child directive template
Directive-to-Directive communication
How to create a DSL in Angular
<div ng-if="active" ng-transclude></div>
We want to show that tab only if it’s active.
That’s why we are using ng-if
82. 3. Parent directive definition example
angular.module("myApp", [])
.directive("tabs", function() {
return {
transclude: "true"
templateUrl: "partials/tabs.html",
controller: function() {
this.tabs = [];
this.registerTab = function(tab) {
this.tabs.push(tab);
}
}
};
});
Directive-to-Directive communication
How to create a DSL in Angular
83. 4. Parent directive template
Directive-to-Directive communication
How to create a DSL in Angular
<ul class="tabs">
<li ng-repeat="tab in ctrl.tabs">
<button ng-click="ctrl.selectTab(tab)">
{{tab.title}}
</button>
</li>
</ul>
<div ng-transclude></div>
http://jsbin.com/vadalo/edit
The complete example:
85. Suggested Teaching Materials
ng-book
The AngularJS bible
● Complete overview of the framework
● Online labs
http://egghead.io/
Basic to advanced video trainings
● Life's too short for long boring lectures