2. GOALS & ASSUMPTIONS
• We’re
all familiar with basic Javascript & HTML & MVC
terminology, but maybe not Angular’s take on it.
• Yeoman
is awesome. But the Yeoman way and the basic
(naïve) way aren’t really compatible in a 2-hr session. We’ll
leave Yeoman for another day.
•I
wish there was more time for audience hands-on tonight, but
Angular’s a big topic. So, all the demo code is available for
take-home experimentation.
• Save
questions for breaks & the end, pls. I’ll stick around.
Friday, November 15, 13
3. ANGULAR BUZZWORDS
Full Application Framework,
not a Library
• MV*
• Convenient Abstractions
• Total Modularity, Reusability
• Pub-Sub Communications
Between Modules
• Dependency Injection
• Routing, Deep-Linking, History
• Filters, Expression Interpolation
•
Friday, November 15, 13
Data-Binding
• HTML Templating
• Testing Baked-In (Karma)
• Integrated Promises ($Q)
• Localization
• Form Validation
• “Big UI”
• MIT License
•
4. ANGULAR IS ALL ABOUT...
• MV*: A
data model, templates for viewing/interacting with it,
and logic in controllers, services, directives, etc.
• Declarative
Behavior: Protect Extend HTML. HTML is
right for templates, not JS. Intentions are visible in templates.
• Data-Binding: User
or Program can modify the model, and
views update automagically to reflect those changes.
• Model-Driven
Behavior: DOM / View updates based on
model, not brittle imperative logic. Truth in DOM Model.
• Modular
Architecture, Separated Concerns: DOM
changes in Directives, model changes in Controllers, abstracted
app-wide support functions & data in Services
Friday, November 15, 13
7. Bootstrapping
Your App
The ng-app directive tells Angular
what part of your main template it
needs to watch. It ‘wakes up’
Angular.
You can (should) define a specific
Angular module to serve as the core
app logic: ng-app=‘myModule’
You can also bootstrap manually, if
you need to.
Friday, November 15, 13
8. Data-Binding
Angular’s declarative 2-way databinding is part of its special sauce.
Changing data
automagically
Changing data
automagically
in the model
updates the view.
in the view
updates the model.
model -> view -> model -> view
LET ANGULAR DO THIS FOR YOU! It’s
part of Angular’s emphasis on
model-driven UI.
Friday, November 15, 13
9. DOM
Then
shows final
outcome in
the DOM
Angular
watches for
changes
here
Don’t do
imperative DOM
Changes!
Consequent
model changes
by Angular
MODEL
Model
Changes can
start
anywhere
Friday, November 15, 13
Updates the
model
accordingly
Truth
lives Here!
Not in DOM!
10. Tells Angular: “Watch this space”
Tells Angular: “Bind this input.”
Tells Angular: “Insert Data here.”
Friday, November 15, 13
11. But what about those
curly-brackets?
ANGULAR EXPRESSIONS
Friday, November 15, 13
12. With an Angular
Expression, You Can:
Do math, or comparison
Concatenate text
Reference a model property
Invoke a function
But not: Control Flow, like
conditions or loops
(app logic belongs in controllers)
Friday, November 15, 13
13. One more thing you
can do:
Filter the output of the expression
Filters are applied by ‘piping’ an
expression into one:
{{modelName.propertyName
|
filterName:arg}}
Friday, November 15, 13
15. So, How Can we Build
a More Complicated
App Than This?
Organize code with
MODULES
Friday, November 15, 13
16. Modules are where we put our code:
like filters, controllers,
directives, services, and
configuration information.
They provide us with encapsulation
and re-usability for macro-level
groupings of code.
Note that
angular.module(‘moduleName’) is both
a creator and a retriever.
Friday, November 15, 13
17. And when we want to
organize our data
(view-models), too?
Organize view data
& functions with
CONTROLLERS
Friday, November 15, 13
18. Controllers Intro
Controllers are function Instances, used
for interacting w/ data in views:
They’re created and destroyed along
with elements/templates.
multiple invocations = multiple
instances
If you want persistence, either place
on an element that’s persistent, or
place the data/methods in a service
(more later).
Hard to address a *specific*
controller, so use events for
communication (more later).
Friday, November 15, 13
20. Services Intro
Services are ludicrously simple:
Remember (from, like, 1 slide ago),
how controllers are created and
destroyed every time you need one?
And there can be lots of instances of
a single controller type?
Services, by contrast, are unicorns,
and last forever.
(jargon: ‘lazy-loaded singletons’)
Friday, November 15, 13
21. Templates/Views Intro
In Angular, HTML is the template
language!
Use inline HTML, external files, or
simple strings as templates.
Then use expressions (and directives)
to insert data from your model into
the view.
Re-use templates with different
controllers, re-use controllers with
different templates.
Friday, November 15, 13
23. Routing Intro
Since we’re extending HTML in our
templates, let’s extend the browser
too.
Routing lets you drive your interface
views using the content of the
location/URL bar.
This lets our Angular Apps behave
just like the server-side apps that
users are used to, with forward/back
and deep-linking to specific content.
Friday, November 15, 13
25. Directives Intro
Controllers are just for data
interactions. So DOM code has to go
somewhere. Directives it is.
Modular, re-usable, de-coupled DOM
logic. Directives embody all of
Angular’s major design principles.
Way easier to use than the (old)
Angular docs make it seem. We’ll have
you writing your own in no time.
Friday, November 15, 13
26. Directive Pop-Star:
NG-REPEAT
Everybody digs it: throw a series of
data into your view super-easily.
Like ‘collection-views’ in other
libraries
filter/sort the output if you like
Friday, November 15, 13
30. About Controllers
Best-practice: use controller only
for dealing with data/model. Let
directives handle updating the views
based on the properties of the model.
Two ways to define:
using .controller() method on a
module
As an ordinary named function
(This will wind up on global
scope. No good reason to do this.
Just recognize it if you see it.)
Friday, November 15, 13
32. Templates Demo
Note: when we provide the name of a
template in the declaration of a
directive like ng-include, we have to
wrap it in a second pair of quotes.
The first pair of quotes delimits an
expression, which will be eval()’d by
Angular. Since we supply a template
path as a string, it needs the
quotes. We could also reference a
property on the model, without
needing to do that.
Friday, November 15, 13
33. Templates/Views
We can include templates
conditionally, using directives like
ng-show/ng-hide, ng-if, ng-switch
(We’ll also demonstrate how to use
custom directives as another way to
include a template.)
But the most powerful way to
conditionally show content, is to use
the browser’s address bar. Which
means we want...
Friday, November 15, 13
34. Templates SNAFU
Browsers don’t like to let you access
external local files. This sets off ‘sameorigin’ errors. Simple solution: start a
server. Painless Javascript/Node approach:
>>
sudo
npm
install
-‐g
http-‐server
>>
http-‐server
(or:
`node
bin/http-‐server`)
But, no logging!
‘Ole-reliable Python option with logging:
>>
python
-‐m
SimpleHTTPServer
8000
Or, the faster ‘Twisted’ (comes w/ OSX):
>>
twistd
-‐no
web
-‐-‐path=.
Friday, November 15, 13
35. Templates SNAFU
Or, you can just use Yeoman/Grunt:
>>
grunt
server
(do this)
Friday, November 15, 13
37. First: $location
Angular’s $location service is bound
to window.location (ie. to what’s in
the browser’s ‘address bar’)
Changes to the URL in the address bar
are reflected in $location & changes
to $location are reflected in address
bar.
‘Back’ & ‘Forward’ are supported, as
is deep-linking
See: “Using $location” guide
Friday, November 15, 13
38. $route
The $route service (configured via
$routeProvider) gives us the ability
to react programmatically to changes
in the $location (plus $routeParams).
We specify a template that will be
rendered inside an <ng-view> in
response to a given route-change,
along with its controller and some
other details.
Friday, November 15, 13
39. Routing Is A Config
For Your App Module
Fundamentally, routing works as a
configuration detail on your base
application module. (The one in ng-app.)
There are two ways to configure your
app: by supplying a config function at
module creation, or by invoking the
config function on your app after
creation...
Friday, November 15, 13
40. 2 Ways to Config App
A config function is the (unpopular)
third argument to a module’s creation:
myModule = angular.module(name, [dependencies],
function(injectables) {
// Configuration details, like routing
});
Or, after the fact w/ Module.config( )
myModule.config(function(injectables) {
// Configuration details, like routing
});
Friday, November 15, 13
41. Routing Syntax
Routes are added via configuration
methods called on $routeProvider in
the app config function.
There are only two basic methods
involved:
$routeProvider.when(path, route)
$routeProvider.otherwise(params)
Friday, November 15, 13
42. Route Config Object
We can include an optional route config
object for each path, with the following
options:
template: html template as string
templateUrl: path to a partial
controller: binds an instance of
specified controller to the template
instance
redirectTo: a path string or a function
that returns one
resolve: a function or service reference
that will execute (or promise that
resolves) before $routeChangeSuccess
Friday, November 15, 13
43. Routing Example
myModule.config(function($routeProvider) {
$routeProvider
.when('/home', { templateUrl: 'home.html',
controller: homeCtrl })
.when('/index', { redirectTo: '/home’ })
.when('/archive/doc/:docId',
{ templateUrl: 'archive_doc.html',
controller: archCtrl })
.when('/contact', { templateUrl: 'poc.html',
controller: pocCtrl,
resolve: {
// I will cause a 1 second delay
delay: function($q, $timeout) {
var delay = $q.defer();
$timeout(delay.resolve, 1000);
return delay.promise; }})
.otherwise({ redirectTo: '/home' });
});
Friday, November 15, 13
44. .otherwise()
The only property in the .otherwise()
config object is redirectTo
NOTE: the value of redirectTo should be a
path, like ‘/home’, not a template location
like ‘home.html’. The route for ‘/home’
will then take care of supplying the
template.
myModule.config(function($routeProvider) {
$routeProvider
.when('/home', { templateUrl: 'home.html',
controller: homeCtrl })
.otherwise({ redirectTo: '/home' });
});
Friday, November 15, 13
45. Named Groups in Path
The path can contain ‘named groups’
starting with a colon (/path/path/:name).
All characters between colon and next
slash are matched and stored in
$routeParams.
From $routeParams, you can access that
data and use it in preparing the view,
based on related data.
Good technique for dynamically including
data from a collection: users, products,
chapters, etc.
Friday, November 15, 13
46. Named Groups in Path
example definition from Angular docs:
$routeProvider.when('/Book/:bookId/ch/:chapterId',
{templateUrl: 'chapter.html',
controller: ChapterCntl
});
Example URL:
//docs.angular.org/Book/Gatsby/ch/4
The Route Params you’ll see for that:
$routeParams = {"bookId":"Moby","chapterId":"1"}
Friday, November 15, 13
48. ‘Models’
Unlike Ember, Angular doesn’t force
you into creating OOP models using
their abstractions. Do as you like.
But model data should reside in
objects that are properties on the
$scope (‘model objects’, if you
will), not directly in properties of
the scope. Operations upon properties
stored directly on $scope can have
unexpected results. This is *totally*
undocumented, but comes from Angular
core team.
Friday, November 15, 13
49. WTF is $scope ???
So, if Angular models are just plainold Javascript objects (POJOs), what
do we need this $scope thing for?
Dependency Injection
Angular will
the correct,
you need it:
controllers,
use DI to make sure that
contextual data is where
in re-usable
directives & views.
$scope also gives us inheritance, via
a DOM-like tree. Data available to
app root is also available on leaves.
Friday, November 15, 13
53. Services in Detail:
Why Services?
Provide re-usable, testable modular
utilities across the application
Abstract implementation details, and
simply provide a convenient API to
other parts of the application.
Provide persistent application state
across controller, view & directive
*instances*
Friday, November 15, 13
54. Services in Detail
‘Back-office’ functions, like
networking, event-dispatch, etc.
Lazy-loaded singleton modules that
persist through the life-cycle of the
app, once instantiated.
Injected dependencies that can be
used by any other module
Examples: $http, $log, $location,
$route, & services used only by
Angular: $provide, $injector, $parse
Friday, November 15, 13
55. Services: A Metaphor
In some ways, an Angular Service is
little more than a stateful,
application-wide controller.
Friday, November 15, 13
56. How are custom Services
different from built-ins?
They’re not.
At all.
No, really.
(Well, OK: they’re different in
naming conventions: don’t use ‘$’ in
your custom services.)
Friday, November 15, 13
57. Defining Services
There are wayyy too many patterns for
defining a service, and the Angular
docs fail to even mention the simplest,
most intuitive one, using the
module’s .service() convenience method
(which also aliases to .factory):
var app = angular.module('appModule',
['dependency1']);
app.service(‘serviceName’, function() {
return shinyNewServiceInstance;
});
Friday, November 15, 13
58. Defining Services
The older version of service creation,
which you’ll still find in the docs,
involves the module’s config function
and calling .factory (or .service) on
$provide:
angular.module('appModule',[‘dependency1’])
.config(function($provide) {
$provide.factory('serviceName', function() {
return shinyNewServiceInstance;
});
});
Friday, November 15, 13
60. shinyNewServiceInstance
Relax! Here, we get to rely on
standard JS pragmatics:
return either a single
function or a revealed module,
as you wish
allows public & private
properties in the constructor
Friday, November 15, 13
61. Single-Function Service
angular.module('appModule', [], function($provide) {
$provide.factory('notifySvc', function() {
var msgs = []; //private variable
return function(msg) { //public function
msgs.push(msg);
if (msgs.length == 3) {
alert(msgs.join("n"));
msgs = [];
}
};
});
Just call with notifySvc(msg), after
injecting into a controller or directive
Friday, November 15, 13
62. Multi-Property Service
angular.module('appModule', [])
.service('notifySvc', function() {
var msgs = []; //private variable
return {
submit: function(msg) { msgs.push(msg); },
dump: function() {
if (msgs.length == 3) {
win.alert(msgs.join("n"));
msgs = [];
}
};
}});
Just call with notifySvc.submit(msg) and
notifySvc.dump()
Friday, November 15, 13
63. Service Instantiation
Remember: Services are ‘lazy-loaded
singletons’. That means the service
instance won’t actually be created
until you specifically need it.
You tell Angular you need it by
injecting it into a controller,
directive, etc.
Friday, November 15, 13
64. Referencing Services
In a directive or controller, you can
have direct access to a service and
its properties, assuming you have
injected it properly.
In HTML (an interpolated expression),
you can’t reference until you’ve
attached it to local $scope. So, in
your controller:
$scope.property = serviceName.serviceProperty;
Friday, November 15, 13
68. What Are They, Really?
5(-ish) words:
Logic & Behavior For UI
“...a way to teach HTML new tricks.”
Anything in your app that touches DOM
Examples: event-handling, behavior
management, template pre-processing &
insertion, data-binding, ‘Collection
Views’, UI Widgets, conditional
display, i18n & localization, etc.
Friday, November 15, 13
69. What Are They, Really?
The only other Angular construct that
really touches the DOM is:
Angular Expressions (text only).
Filters
The rest of it should be in
Directives. (Even the ng-view that
executes your routing is simply a
model-driven directive...)
Friday, November 15, 13
70. What Are They, Really?
Structurally speaking, a Directive is
just a function that’s attached to an
element.
But not just a function: a whole
execution environment. Really,
Directives are mini-applications.
You can think of them as little
robotic pilots that live on your DOM
elements & tell them what to do.
Friday, November 15, 13
76. Why Declarative?
IMPERATIVE = YOUR PROBLEM
DECLARATIVE = SOMEBODY ELSE’S PROBLEM
Easier To Read, Maintain: Why scatter
event-listeners across 100 linked JS
files, then need to go search for
them to find out what’s happening on
an element.
Friday, November 15, 13
77. Declarativeness ROCKS
You’re trying to find handlers for
this element:
<button id=”1” class=”B C”></button>
Well, where are the event-handlers?
On ‘#1’? On ‘.B’? ‘.C’? On ‘button’?
What if it’s on ‘parentDiv>:firstchild’?
You can’t misunderstand what’s
happening with declarative directives:
<button md-action-handler></button>
Friday, November 15, 13
78. Extending HTML...
HTML is NOT a virgin bride or
hothouse flower.
The Semantics Wars are over. HTML is
a highly-abstracted, Object-Oriented
language for app interfaces and for
*presenting* documents. Docs
themselves are increasingly stored in
other formats, like markdown.
We’re not abandoning accessibility.
But it’s not a binary choice, anyway.
Friday, November 15, 13
80. Reusability
It’s all about context-awareness,
data-binding & DI.
Directives know their own element and
local scope.
You can pass additional data into
directives as attributes, right on
the element.
Friday, November 15, 13
84. Yes: ‘Local’
Sticks to a self-contained, modular
scope, which understands its context:
inside the directive, `element` is
like `this`.
Uses messages, models to affect
things elsewhere.
Easier to maintain, easier to read,
easier to scale.
But the challenge to all that is:
Friday, November 15, 13
85. My Awesome Website
Needs to
Change
Things Here
Sweet Product
Cart: 1 Item(s)
$899.99
Buy Now!
Product Description: Lorem ipsum
dolor sit amet, consectetur
adipiscing elit. In erat mauris,
faucibus quis pharetra sit amet,
pretium ac libero. Etiam vehicula
eleifend bibendum. Morbi gravida
metus ut sapien condimentum sodales
mollis augue sodales. Vestibulum
quis quam at sem placerat aliquet.
Curabitur a felis at sapien
ullamcorper fermentum. Mauris
molestie arcu et lectus iaculis sit
amet eleifend eros posuere. Fusce
nec porta orci.
Clicking Here
Friday, November 15, 13
Integer vitae neque odio, a
sollicitudin lorem. Aenean orci
mauris, tristique luctus fermentum
eu, feugiat vel massa. Fusce sem
87. Directive Names
Angular uses a convention borrowed
from other JS projects: names in HTML
are hyphenated...
<sample-directive></sample-directive>
while identifiers in the JS are
camel-cased:
.directive(‘sampleDirective’, function(){})
Expect Angular to do this conversion
automatically. Don’t fight it.
Friday, November 15, 13
88. How are custom directives
different from built-in?
They’re not.
At all.
No, really.
(Well, OK: they’re different in
naming conventions: don’t use ‘ng-’
in your custom directives.)
Friday, November 15, 13
89. CREATION
.directive() is a method we call on
an angular.module(), either at
creation time or via reference,
passing a name and a factory function
angular
.module('moduleName', ['dependency1', 'dependency2'])
.directive('directiveName', factoryFunction() {})
The factory will return either a
function or an object containing a
function and other settings
Friday, November 15, 13
90. Factories
(Note, when we talk about generic
‘factories’, we don’t mean $factory,
which is an Angular implementation
service.)
The factory pattern is all about
Functional Programming: using basic
Javascript functions to build and
return either naiive objects or other
functions.
Friday, November 15, 13
91. What do We Do With
The Factory
Function?
Friday, November 15, 13
97. Using a Config Object
angular.module('moduleName').
directive('sampleDirective', function(){
return {
link: function(scope, element, attrs) {
// this example binds a behavior to the
// mouseenter event
element.bind("mouseenter", function(){
... do stuff after mouseenter ...
}
},
restrict: ‘E’,
template: “<div>Hello, World!</div>”
}})
Everything but `link` is optional.
Friday, November 15, 13
98. Link Function Args
.directive('sampleDirective', function(){
return {
link: function(scope, element, attrs) {
// this example binds a behavior to the
// mouseenter event
element.bind("mouseenter", function(){
... do stuff after mouseenter ...
}
},
restrict: ‘E’,
template: <div>Hello, World!</div>
}
})
Friday, November 15, 13
99. Link Function Args
3 standard params for a link function.
(Plus optional 4th: controller.) They’re
supplied as args by the directive function,
if specified.
scope: whatever scope object is local
element: element declared on: `this`
attrs: an object containing the html
attributes defined on the element,
including the directive invocation itself
Supplied to the function not by name but in
order. Call them whatever you want.
Friday, November 15, 13
100. jqLite:
your path to the DOM
Angular will defer to JQuery, if
present, but provides its own subset
of JQuery for basic DOM tasks.
You can’t just use $(), nor find
using selectors, unfortunately.
But all built-in `element` refs are
already pre-wrapped in jqlite object
Chain methods as you normally would
Friday, November 15, 13
105. A Thought:
If angular.element() / jqlite doesn’t
support what you’re trying to do...
ask yourself: why not?
Because they’re lazy bastards?
Not so much. Think about other options.
Go with the grain, and Angular will
reward you.
Friday, November 15, 13
106. Directive Templates
Templates can be stored as strings on
the `template:` property
They can also be loaded from a file,
using:
`templateUrl: path/to/file/template.html’
Friday, November 15, 13
107. Templates
.directive('sampleDirective', function(){
return {
link: function(scope, element, attrs) {
// this example binds a behavior to the
// mouseenter event
element.bind("mouseenter", function(){
... do stuff after mouseenter ...
}
},
restrict: ‘E’,
template: ‘<div>Hello, World!</div>’
//or:
templateUrl: ‘path/to/file.html’
})
Friday, November 15, 13
108. The Restrict Property
.directive('sampleDirective', function(){
return {
link: function(scope, element, attrs) {
// this example binds a behavior to the
// mouseenter event
element.bind("mouseenter", function(){
... do stuff after mouseenter ...
}
},
restrict: ‘E’,
template: <div>Hello, World!</div>
}
})
Friday, November 15, 13
109. The Restrict Property
Remember that directives are re-usable
So, we can restrict the usage of a
directive to (a) specific context(s), so
that we don’t accidentally try to use it
in a situation it wasn’t designed for:
‘E’ = Element
‘A’ = Attribute
‘C’ = Class
‘M’ = Comment
Stack as a single string: ‘EACM’.
Defaults to ‘A’.
Friday, November 15, 13
110. The Replace Property
By default, a directive element will
wrap the contents of a template. The
`element` object will be the outer
directive element.
To instead replace the directive
element (and object) with the contents
of the template, use {replace: true}
This is esp critical when declaring as
an element...
Friday, November 15, 13
114. Why Model-Driven?
After all, the imperative
approach works fine...
...if you’re omniscient
and precognitive.
... and you really, really
like refactoring.
Friday, November 15, 13
118. How Can Directives
React to Stuff that
Happens Far, Far Away?
Again, with models & $watch!
But sometimes, the inheritance
chain isn’t a good solution. For
those times...
Angular events!
$on(), $emit(), $broadcast()
Friday, November 15, 13
119. Advanced Topic:
Inter-Scope Communication
Use $watch to monitor properties of
local $scope or one it inherits from
That works great when you only need
data to flow in one direction (up)
and only on one branch of the tree.
What about when you need to go
downwards, or sideways?
Or a whole bunch of places at once?
Friday, November 15, 13
121. Angular Events to
The Rescue!!!
Just like how a ‘click’ event bubbles
up through the DOM tree, you can
$emit() an Angular event up the
$scope tree, from any starting point.
Better than the DOM, you can also
$broadcast() an event down the $scope
tree.
$broadcast()-ing from $rootScope gets
you the whole shebang.
Friday, November 15, 13
123. Angular Events to
The Rescue!!!
With events, there’s no need to
laboriously climb your way up the
$scope tree. You also eliminate the
chance of getting the wrong scope.
You also get full de-coupling of a
controller/directive from a
particular place in your app. Use it
anywhere, $broadcast() everywhere.
Friday, November 15, 13
124. Angular Events to
The Rescue!!!
And you don’t even need to predict
who all the recipients will be. By
sending:
$rootScope.$broadcast(‘gameOver’)
your whole app gets the information,
You can consume the event as many
places as you like, with:
$scope.$on(‘gameOver’, handlerFunc)
Friday, November 15, 13
127. 2 Excellent New
Tutorials:
ng-newsletter’s “Beginner to Expert”
series: http://www.ng-newsletter.com/
posts/beginner2experthow_to_start.html
Thinkster.IO’s “A Better Way to Learn
AngularJS”: http://www.thinkster.io/
pick/GtaQ0oMGIl/a-better-way-tolearn-angularjs
Friday, November 15, 13
130. Angular 1.2 New
Features
The new animations, in particular,
are super-righteous: declare standard
CSS animations in classes, then
Angular will apply them while
migrating content in and out of the
DOM.
Friday, November 15, 13