Beruflich Dokumente
Kultur Dokumente
Routes
Wiring Together Views Section 1
Logic in Our Routes Section 2
Directives
$scope Section 1
Services
5 Recipes and a Factory Section 1
Another Factory Section 2
Provider Section 3
$resource Section 4
Reusable Directives
Children and Parents Communicate Section 1
Filters Section 2
External libraries Section 3
Note Wrangler
notes-index.html
users-index.html
css
application.css
images
templates
Note Wrangler
notes-index.html
users-index.html
css
javascript
app.js
Note Wrangler
notes-index.html
users-index.html
css
javascript
app.js
controllers.js
lters.js
services.js
directives.js
controllers
lters
services
directives
templates
Note Wrangler
notes-index.html
users-index.html
css
javascript
app.js
K e e p t h in g s
e n c a p s u la t e d a n d b it e -s
iz e
controllers
notes-create-controller.js
notes-edit-controller.js
notes-index-controller.js
notes-show-controller.js
lters
services
directives
templates
Note Wrangler
notes-index.html
users-index.html
css
javascript
templates
notes-index.html
<!DOCTYPE html>
<html lang="en" ng-app="NoteWrangler">
<head>
<meta charset="utf-8">
<title>Note Wrangler</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="css/application.css" />
</head>
<body>
<div class="nav-wrapper has-dropdown">
<div class="nav-content">
<div class="wrapper">
<div class="nav-content-layout">
<div class="nav-list">
<a href="#/"
class="list-item"
notes-index.html
<div class="main-wrapper">
<div class="note-wrapper">
<div class="note-content">
<div class="notes-header">
<h1 title="Notes">Notes</h1>
</div>
<div class="note-wrapper">
<a class="card-notes" ng-repeat="note in notes">
<div class="card" title="{{note.title}}">
<h2 class="h3">{{note.title}}</h2>
<p>{{note.description}}</p>
</div>
</a>
</div>
</div>
</div>
</div>
users-index.html
notes-index.html
<div <div
class="main-wrapper">
class="main-wrapper">
<div class="note-wrapper">
<div class="users-wrapper">
<div class="note-content">
<h1>Users</h1>
<div class="notes-header">
<h1 title="Notes">Notes</h1>
</div><div class="users-wrapper">
<a class="card-users" ng-repeat="user in users">
<div class="card" title="{{user.name}}">
<div class="note-wrapper">
<h2 class="h3">{{user.name}}</h2>
<a class="card-notes"
ng-repeat="note in notes">
<p>{{user.bio}}</p>
</div>
<div class="card"
title="{{note.title}}">
</a>
<h2
class="h3">{{note.title}}</h2>
Unique chunk inside
</div>
<p>{{note.description}}</p>
</div>
</div>
</a>
</div>
</div>
<!-- Load Js libs -->
<script src="./js/vendor/jquery.js"></script>
</div>
<script src="./js/vendor/angular.js"></script>
</div>
<script src="./js/vendor/angular-route.js"></script>
users-index.html
<div class="users-wrapper">
<div class="note-wrapper">
<h1>Users</h1>
<div class="note-content">
<div class="notes-header">
<div class="users-wrapper">
<h1 title="Notes">Notes</h1>
<a class="card-users" ng-repeat="user in users">
</div>
<div class="card" title="{{user.name}}">
<h2 class="h3">{{user.name}}</h2>
<div class="note-wrapper">
<p>{{user.bio}}</p>
<a class="card-notes" ng-repeat="note in notes">
</div>
</a>
<div class="card" title="{{note.title}}">
</div>
<h2 class="h3">{{note.title}}</h2>
<p>{{note.description}}</p>
</div>
</div>
</a>
</div>
Note Wrangler
index.html
css
templates
pages
notes
notes-index.html
users
users-index.html
notes-index.html
k<div
class="note-wrapper"> ...
users-index.html
<divindex.html
class="users-wrapper">...
We can eliminate the duplication and remove the prex on our les.
Note Wrangler
index.html
css
templates
pages
notes
index.html
users
index.html
notes-index.html
notes/index.html
k<div
class="note-wrapper"> ...
users/index.html
users-index.html
users/index.html
<divindex.html
class="users-wrapper">...
We can eliminate the duplication and remove the prex on our les.
Note Wrangler
index.html
css
templates
pages
notes
index.html
users
index.html
Unique content
removed
Add ng-app
Note Wrangler
index.html
css
templates
pages
notes
index.html
users
index.html
javascript
Note Wrangler
index.html
css
templates
pages
notes
index.html
users
index.html
javascript
Note Wrangler
index.html
css
templates
pages
notes
index.html
users
index.html
javascript
_ Dening a Route
Angular routes allow us to map URLs to use templates so that every time the current route changes,
the included view changes with it.
Note Wrangler
index.html
css
templates
pages
notes
index.html
users
index.html
javascript
routes.js
http://example.com/#/notes
Using ngView
Dening routes
a Using ngView
This allows us to tell our Angular app where to load in templates that we will wire together shortly.
index.html
notes/index.html
users/index.html
angular.module('NoteWrangler')
.config(function($routeProvider){});
Well use $routeProvider in a minute to specify Routes.
_ Creating routes.js
Why arent we doing it the way we learned in Shaping up with Angular.js?
Setting your app module to a variable and reusing that variable is bad practice.
routes.js
angular.module('NoteWrangler')
.config(function($routeProvider){});
angular.module('NoteWrangler')
.config(function($routeProvider) {
$routeProvider.when('/notes', {
templateUrl: '/templates/pages/notes/index.html'
})
});
angular.module('NoteWrangler')
.config(function($routeProvider) {
$routeProvider.when('/notes', {
templateUrl: 'templates/pages/notes/index.html',
})
});
.when('/users', {
templateUrl: 'templates/pages/users/index.html',
})
Note Wrangler
index.html
css
templates
pages
notes
index.html
users
index.html
angular.module('NoteWrangler')
.config(function($routeProvider) {
$routeProvider.when('/notes', {
templateUrl: 'templates/pages/notes/index.html',
})
...
.when('/', {
templateUrl: 'templates/pages/notes/index.html',
})
});
angular.module('NoteWrangler')
.config(function($routeProvider) {
$routeProvider.when('/notes', {
templateUrl: 'templates/pages/notes/index.html',
})
...
.when('/', {
templateUrl: 'templates/pages/notes/index.html',
})
.otherwise({ redirectTo: '/' });
});
.otherwise(params);
Sets route denition that will be used on route change when no other route denition is matched.
Brackets
Node
Ruby on Rails
and so many more
Routes
Logic in Our Routes Section 2
});
Routing Components
Not only can routes have templates associated with them, but they can also have their own
associated controllers.
Requests
/notes
controller
template
/users
controller
template
redirect
Note Wrangler
notes-index.html
users-index.html
css
javascript
app.js
notes-index-controller.js
angular.module('NoteWrangler')
.controller('NotesIndexController', function() {
});
controllers
notes-create-controller.js
notes-edit-controller.js
notes-index-controller.js
notes-show-controller.js
lters
services
directives
templates
angular.module('NoteWrangler')
.controller('NotesIndexController', function() {
});
$http.get
retrieve data
notes-index-controller.js
angular.module('NoteWrangler')
.controller('NotesIndexController', function($http) {
var controller = this;
$http({method: 'GET', url: '/notes'}).success(function(data) {
controller.notes = data;
});
});
a Displaying Notes
Now we are ready to display a list of all the notes. We will use ngRepeat to loop through them.
notes/index.html
<div class="note-wrapper">
<a class="card-notes" ng-repeat="note in indexController.notes>
</a>
</div>
a Displaying Notes
With each note instance, we can print out note info on each card.
notes/index.html
<div class="note-wrapper">
<a class="card-notes" ng-repeat="note in indexController.notes">
<div class="card" title='{{note.title}}'>
<div ng-if='icon'>
<i class='icon icon-card {{note.icon}}'></i>
</div>
<h2 class='h3'>{{note.title}}</h2>
</div>
</a>
</div>
notes-show.html
http://example.com/#/notes/<id>
notes[<id>].info
Note is clicked
Route changes
Route loads view
.when('/notes/:id', {
templateUrl: 'templates/pages/notes/show.html',
controller: 'NotesShowController',
controllerAs: 'showController'
})
/notes/1
angular.module('NoteWrangler')
.controller('NotesShowController', function($http, $routeParams) {
var controller = this;
$http({method:'GET', url: '/notes/' + $routeParams.id})
.success(function(data){
this keyword
controller.note = data;
})
});
Assign to a variable in order to use this keyword inside the callback.
Directives Level 2
$scope Section 1
...
<div class="note-wrapper">
<a class="card-notes" ng-repeat="note in notes"
ng-href="#/notes/{{note.id}}">
<div class="card">
<h2 class="h3">{{card.header}}</h2>
</div>
</a>
</div>
...
...
<div class="note-wrapper">
<a class="card-notes" ng-repeat="note in notes"
ng-href="#/notes/{{note.id}}">
</a>
</div>
...
nw-card.html
<div class="card">
<h2 class="h3">{{card.header}}</h2>
</div>
...
<div class="note-wrapper">
<a class="card-notes" ng-repeat="note in notes" >
<nw-card></nw-card>
</a>
nw-card.js
</div>
...
angular.module("NoteWrangler")
.directive("nwCard", function() {
return {
restrict: "E",
templateUrl: "templates/directives/nw-card.html"
};
});
nw-card.js
angular.module("NoteWrangler")
.directive("nwCard", function() {
return {
restrict: "E",
templateUrl: "templates/directives/nw-card.html"
};
});
angular.module("NoteWrangler")
.directive("nwCard", function() {
return {
restrict: "E",
templateUrl: "templates/directives/nw-card.html",
controller: function(){
};
});
},
controllerAs: "card"
angular.module("NoteWrangler")
.directive("nwCard", function() {
return {
restrict: "E",
templateUrl: "templates/directives/nw-card.html",
controller: function(){
this.header = "Note Title";
},
nw-card.html
controllerAs: "card"
<div class="card">
};
<h2 class="h3">{{card.header}}</h2>
});
</div>
nw-card.html
<div class="card">
<h2 class="h3">{{header}}</h2>
</div>
nw-card.js
controller: function($scope) {
this.header = "Note Title";
},
controllerAs: "card"
controller: function($scope) {
$
$scope.header = "Note Title";
}.
nw-card.html
nw-card.html
<div class="card">
<h2 class="h3">{{card.header}}</h2>
</div>
<div class="card">
<h2 class="h3">{{header}}</h2>
</div>
S a m e r e s u lt
Directives Level 2
Scope the Config Object Section 2
Current Code
nw-card.js
angular.module("NoteWrangler")
.directive("nwCard", function() {
return {
restrict: "E",
templateUrl: "templates/directives/nw-card.html",
$
};
});
controller: function($scope){
$scope.header = "Note Title";
}
Understanding $scope
We are going to simplify our note example and add numbers to the headers.
notes.html
...
<div class="note-wrapper">
<a class="card-notes">
<nw-card></nw-card>
<nw-card></nw-card>
<nw-card></nw-card>
<nw-card></nw-card>
</a>
</div>
example/nw-card.html
<div class="card">
<h2 class="h3">{{header}}</h2>
</div>
nw-card.js
angular.module("NoteWrangler")
.directive("nwCard", function() {
var num = 1;
return {
restrict: "E",
templateUrl: "example/nw-card.html",
controller: function($scope){
$scope.header = "Note Title" + num++;
};
});
div scope
header
nw-card scope
div scope
header
nw-card scope
G iv e t h is d ir e c t iv e
it s o w n s c o p e !
It s W O R K IN G !
i scope: false
t
c lt
e
r au
i
D f
d e Inherited Scope
div scope
scope: { }
Isolate Scope
div scope
header
nw-card scope
nw-card scope
header
nw-card.html
No access!
<div class="card">
<h2 class="h3">{{note.header}}</h2>
</div>
How can we use isolate scope and still access our notes array with titles?
Setting note.title
to a header var
nw-card.html
<div class="card">
<h2 class="h3">{{header}}</h2>
</div>
Two-way Binding
So if the value gets changed, it gets changed everywhere.
nw-card.js
angular.module("NoteWrangler")
.directive("nwCard", function() {
return {
restrict: "E",
templateUrl: "templates/directives/nw-card.html",
scope: {
header: "=" = two-way binds an object
}.
};
});
<nw-card header="note.header"></nw-card>
nw-card.html
<div class="card">
<h2 class="h3">{{header}}</h2>
<i class="icon icon-card {{icon}}"></i>
</div>
Directives Level 2
Link Section 3
nw-card.html
<div class="card">
<h2 class="h3">{{header}}</h2>
<p class="hidden">{{description}}</p>
</div>
When someone clicks, we want to toggle .hidden class.
style.css
.card {
position: relative;
}
...
.card p.hidden {
display: none;
}
Introducing Link
The link function is run after our directive has been compiled and linked up.
nw-card.js
angular.module("NoteWrangler")
.directive("nwCard", function nwCardDirective(){
return {
link: function(){
$("div.card").on("click", function(){
$("div.card p").toggleClass("hidden")
}.
}/
...
This is the best spot to do any DOM manipulation or logic functionality for your directive!
angular.module("NoteWrangler")
.directive("nwCard", function() {
return {
...
scope: {
header: "=",
body: "=",
...
},
link: function(scope, element) {
scope.body = markdown.toHTML( scope.body );
angular.module("NoteWrangler")
.directive("nwCard", function($sce) {
return {
...
link: function(scope, element) {
scope.body = $sce.trustAsHtml( markdown.toHTML(scope.body));
}
Strict Contextual Escaping service tells Angular, I trust this as HTML;
dont worry about escaping HTML that could be potentially unsafe.
Services Level 3
Note Wrangler
index.html
css
js
app.js
controllers
app.js
lters
directives
templates
This code is ne, but its not reusable across other parts
of our application. It is also going to be harder to test.
Note Wrangler
Controller
index.html
css
js
app.js
controllers
directives
services
templates
Service
Service
function
function
function
function
Directive
Filter
Note Wrangler
Controller
index.html
css
js
app.js
controllers
directives
services
templates
Service
Service
function
function
function
function
Directive
Filter
Note Wrangler
index.html
css
js
app.js
controllers
directives
services
note.js
templates
Creat e
index.html
...
<ng-view>
<script src="vendor/jquery.js"></script>
<script src="vendor/angular.js"></script>
<script src="vendor/angular-route.js"></script>
<script src="/js/app.js"></script>
<script src="/js/routes.js"></script>
<!-- Services -->
<script src="/js/services/note.js"></script>
</body>
Include
</html>
7 5 Service Recipes
We need to choose a recipe. There are 5 total recipes that range in complexity and customization.
Factory and Provider are the two most commonly used for creating a Service.
Value
Factory
Service
Provider
Constant
2 most common
Provider
Used for sharing methods and objects (like a Factory), but allows for conguration.
Remember the
naming convention
<name> + <recipe>
Factory recipe
angular.module("<ModuleName>")
.factory("<ServiceName>", function <ServiceName>Factory() {
return { <object containing shared functions> }
});
Service
all
create
notes-index-controller.js
angular.module("NoteWrangler")
.controller("NotesIndexController", function($scope) {
$http({method: "GET", url: "/notes"})
.success(function(data) {
$scope.notes = data;
});
});
Services Level 3
Our Problem
We want to show images for each of our users.
bf4ee76b5f3a6bfed26bca5460bc3f22
Template
oller
Contr
Service
Controller
Template
a
Template
http://www.gravatar.com/avatar/bf4ee76b5f3a6bfed26bca5460bc3f22?size=80.png
?size=100
?size=500
http://www.gravatar.com/avatar/bf4ee76b5f3a6bfed26bca5460bc3f22?size=80.png
Gravatar Steps
Back to the steps for how our app can use the Gravatar image:
1. Hash users email into a hash.
alyssa@codeschool.com
bf4ee76b5f3a6bfed26bca5460bc3f22
bf4ee76b5f3a6bfed26bca5460bc3f22
CryptoJS is a simple JavaScript library that has an .MD5 function. Pass this function a string and it
will return that string hash-ied.
CryptoJS.MD5(email)
Include this link to give us access to the above call:
index.html
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/md5.js"></script>
Gravatar Steps
Back to the steps for providing our application with Gravatar images:
1. Hash users email into a hash.
oalyssa@codeschool.com
bf4ee76b5f3a6bfed26bca5460bc3f22
};
});
};
});
To call this service, we need to inject it, and then call the generate function.
Gravatar.generate("alyssa@codeschool.com")
};
});
<div class="users-wrapper">
<a class="card-users" ng-repeat="user in users" ...>
<nw-card header="user.name"
image="gravatarUrl(user.email)"
body="user.bio"
id="user.id">
</nw-card>
</a>
</div>
scope: {
image: "=",
...
}
75 Service Recipes
- Value
Used often
The simplest service recipe used for sharing a value that is used throughout your app repeatedly.
- Factory
- Service
Rarely used
Shares instances of methods and objects.
- Provider
Shares methods and objects (like a Factory), but allows for conguration.
- Constant
Services Level 3
Provider Section 3
- Factory
- Provider
Shares methods and objects (like a Factory), but allows for conguration.
.provider("<Service Name>", function <Service Name>Provider() {
this.$get <function or object of functions>
});
Notice we pass in
GravatarProvider
not just Gravatar
nw-category-select.js
angular.module("NoteWrangler")
.directive("nwCategorySelect", function() {
return {
...
};
});
Should we do this in
controller or link ?
Mocking Up Templates
This directive will be a composite directive with multiple nested templates.
category select
nw-category-select.html
nw-category-item.html
nw-category-select.html
<div class="sort-menu">
<h2>Categories</h2>
<div class="card">
//Child Select Items Go Here
</div>
</div>
nw-category-item.html
nw-category-select.html
<div class="sort-menu">
<h2>Categories</h2>
<div class="card">
<nw-category-item
category select items
ng-repeat="category in categories"
category="category">
</nw-category-item>
</div>
</div>
nw-category-item.html
nw-category-select.html
<div class="sort-menu">
<h2>Categories</h2>
<div class="card">
<nw-category-item ... >
</nw-category-item>
</div>
</div>
nw-category-item.html
<a class="sort-menu-item">
<i class="icon left {{category.icon}}"></i>
{{category.name}} {{categoryCount()}}
</a>
Displaying Categories
Categories are now showing up, but a couple of things need to happen in order to lter these notes
that are being displayed on index.html.
nwCategorySelect
$scope.activeCategory
sample values
nwCategoryItem
"Testing"
nwCategoryItem
"Question"
nwCategoryItem
nwCategoryItem
"Best Practice"
"Code Snippet"
$scope.activeCategory
sample values
"Testing"
"Question"
"Best Practice"
"Code Snippet"
Instead, were going to let nwCategorySelect manage the activeCategory and allow the inner
nwCategoryItems to get or set the active value when they need to.
nwCategorySelect
nwCategoryItem
nwCategoryItem
nwCategoryItem
nwCategoryItem
nw-category-select.js
...
controller: function($scope) {
this.setActiveCategory = function(category){
$scope.activeCategory = category .name;.
};
...
};
...
};
...
scope.makeActive = function(){
nwCategorySelectCtrl.setActiveCategory( scope.category );
}.
Creating categoryActive()
nw-category-select.js
angular.module("NoteWrangler")
.directive("nwCategorySelect", function(Category) {
return {
...
controller: function($scope) {
this.getActiveCategory = function() {
return $scope.activeCategory;
}
}
};
});
...
nw-category-item.html
<a class="sort-menu-item"
ng-click="makeActive()" ng-class="{'active': categoryActive()}" >
<i class="icon left {{category.icon}}"></i> {{category.name}}
</a>
Remember Filters?
A lter is an easy way to format our content before it gets printed in our template.
date
lowercase
uppercase
limitTo
orderBy
| date : "MM/dd/yyyy" }}
02/16/1989
["Alyssa","Angular"]
Were using it to search our array
var notesArray =
[{
"UserId": user.id,
"category": {"name": "Question",
"icon": "question"},
"link" : "",
"description" : "Define Service",
"title" : "What is a Service",
"content": "Service: Angular,
}]
Filt
er
is W
ork
ing!
Chaining Filters
What if we want to use two dierent lters on the same ngRepeat?
index.html
<input ng-model="search.$"/>
...
<div class="note-wrapper">
<a class="card-notes"
ng-repeat="note in notes | filter:activeCategory | filter:search"
ng-href="#/notes/{{note.id}}">
Using another pipe
<nw-card ... ></nw-card>
separate filters
</a>
</div>
<nw-category-select active-category="activeCategory" notes="notes">
</nw-category-select>
to
Chaining lters
angular.module("NoteWrangler")
.directive("title", function() {
return {
restrict: "A",
link: function(scope, element) {
// Append Custom Tooltip here
}.
};
});
}.
title.js
.directive("title", function() {
return function(scope, element) {
};
});
title.js
.directive("title", function() {
return function(scope, element) {
};
});
title.js
angular.module("NoteWrangler")
.directive("title", function() {
return function(scope, element) {
element.tooltip({ container: "body" });
};.
});
Because link is only run one time, it runs before Angular had the value for
{{header}} and then the tooltip is stuck with {{header}} as its text for all time.
title.js
angular.module("NoteWrangler")
.directive("title", function() {
return function(scope, element, $timeout) {
$timeout(function(){
element.tooltip({ container: "body" });
});
};.
});
IC E
BEST PRACT
title.js
angular.module("NoteWrangler")
.directive("title", function() {
return function(scope, element, $timeout) {
...
scope.$on('$destroy', function() {
element.tooltip('destroy');
});
};
});