5. 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, October 4, 13
6. 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, October 4, 13
12. 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, October 4, 13
13. Declarativeness ROCKS
You’re trying to find handlers for
this element:
Well, where are the event-handlers?
On ‘#1’? On ‘.B’? ‘.C’? On ‘button’?
What if it’s on ‘parentDiv>:first-
child’?
You can’t misunderstand what’s
happening with declarative directives:
<button id=”1” class=”B C”></button>
<button md-action-handler></button>
Friday, October 4, 13
14. Why NOT Declarative?
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 religion.
Friday, October 4, 13
16. 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, October 4, 13
20. Yes: ‘Local’
Sticks to a self-contained, modular
scope, which understands its context.
Uses messages, models to affect
things elsewhere.
Easier to maintain, easier to read,
easier to scale.
But the challenge is this:
Friday, October 4, 13
21. My Awesome Website
Sweet Product
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.
Integer vitae neque odio, a
sollicitudin lorem. Aenean orci
mauris, tristique luctus fermentum
eu, feugiat vel massa. Fusce sem
$899.99 Buy Now!
Cart: 1 Item(s)
Clicking Here
Needs to
Change
Things Here
Friday, October 4, 13
23. Directive Names
Angular uses a convention borrowed
from other JS projects: names in HTML
are hyphenated...
while identifiers in the JS are
camel-cased:
Expect Angular to do this conversion
automatically. Don’t fight it.
.directive(‘sampleDirective’, function(){})
<sample-directive></sample-directive>
Friday, October 4, 13
24. 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, October 4, 13
25. 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
The factory will return either a
function or an object containing a
function and other settings
angular
.module('moduleName', ['dependency1', 'dependency2'])
.directive('directiveName', factoryFunction() {})
Friday, October 4, 13
26. 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, October 4, 13
27. What do We Do With
The Factory
Function?
Friday, October 4, 13
33. 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, October 4, 13
34. 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, October 4, 13
35. 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, October 4, 13
36. 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, October 4, 13
41. 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, October 4, 13
42. 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, October 4, 13
43. 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, October 4, 13
45. 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, October 4, 13
46. 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, October 4, 13
47. 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, October 4, 13
51. Why Model-Driven?
After all, the imperative
approach works fine...
...if you’re omniscient
and precognitive.
... and you really, really
like refactoring.
Friday, October 4, 13
55. How Can Directives
React to Stuff that
Happens Far, Far Away?
Also, with models & $watch!
But sometimes, the inheritance
chain isn’t a good solution. For
those times...
Angular events!
$on(), $emit(), $broadcast()
Friday, October 4, 13
57. Often Overlooked:
Controllers
Directive Config Objects can provide
an optional controller.
At first, you think: why?
One option: alternative to routing
Routes have controllers
Sometimes, you don’t want routes
Friday, October 4, 13
58. Often Overlooked:
Controllers
With its own controller, a directive
is a full, standalone interface
component, with its own data context,
which can be built or torn-down on
demand.
Friday, October 4, 13
59. Isolate Scope
We have the option, in directives, of
using either:
the local $scope (from our
controller, possibly)
a new, per-instance, ‘isolate
scope’
Isolate scopes still have a parent
$scope, but they’re *encapsulated*: or,
detached from the inheritance chain.
This is especially useful with repeats,
so variables can be fully local to the
instance
Friday, October 4, 13
60. Creating Isolate Scope
Creating isolate scope is as simple as
an object literal assigned to the
`scope:` property on the config object:
.directive('sampleDirective', function(){
return {
link: function(scope, element, attrs) {
element.bind("mouseenter", function(){
... do stuff after mouseenter ...
}
},
restrict: ‘E’,
scope: {name: “Bob”,
hobby: “@”}
}})
Friday, October 4, 13
62. Isolate Scope Data-Binding
Angular provides us with ways to bind
the value of properties in isolate
scope to attributes on the element,
using special operators:
.directive('sampleDirective', function(){
return {
link: function() {},
restrict: ‘E’,
scope: {name: “Bob”,
hobby: “@”}
//alt. form:{pasttime: ‘@hobby’}
}})
<sample-directive hobby=”scuba-diving”>
Friday, October 4, 13
63. Data-Binding Operators
By default, an operator alone will be
assumed to refer to a same-named attr
Alternately, use form ‘@hobby’ to specify
Options:
‘@’- binds the local scope property to
primitive value of the DOM attribute. Result
is always a string. (Attributes are strings.)
‘=’- binds the local scope property to a
parent scope property having same name as the
value of the DOM attribute.
‘&’- binds the local scope property to the
output of an expression defined in the DOM
attribute. It’s like a function-wrapper.
Friday, October 4, 13