<!doctype html>
<html ng-app>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js">
</script>
</head>
<body>
<div>
<label>Name:</label>
<input type="text" ng-model="yourName" placeholder="Enter a name here">
<hr>
<h1>Hello {{yourName}}!</h1>
</div>
</body>
</html>Hello Angular!
<!doctype html>
<html ng-app>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js">
</script>
</head>
<body>
<div>
<label>Name:</label>
<input type="text" ng-model="yourName" placeholder="Enter a name here">
<hr>
<h1>Hello {{yourName}}!</h1>
</div>
</body>
</html>Hello Anular!
Declares application scope
Declares model/variable binding (with input)
<input type="text" ng-model="yourName" placeholder="Enter a name here">
<h1>Hello {{yourName}}!</h1>
<!doctype html>
<html ng-app="todoApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js">
</script>
<script src="todo.js"></script>
<link rel="stylesheet" href="todo.css">
</head>
<body>
<h2>Todo</h2>
<div ng-controller="TodoListController">
<span>{{remaining()}} of {{todos.length}} remaining</span>
[ <a href="" ng-click="archive()">archive</a> ]
<ul class="unstyled">
<li ng-repeat="todo in todos">
<input type="checkbox" ng-model="todo.done">
<span class="done-{{todo.done}}">{{todo.text}}</span>
</li>
</ul>
<form ng-submit="addTodo()">
<input type="text" ng-model="todoText" size="30"
placeholder="add new todo here">
<input class="btn-primary" type="submit" value="add">
</form>
</div>
</body>
</html>angular.module('todoApp', [])
.controller('TodoListController', function($scope) {
$scope.todos = [
{text:'learn angular', done:true},
{text:'build an angular app', done:false}];
$scope.addTodo = function() {
$scope.todos.push({text:$scope.todoText, done:false});
$scope.todoText = '';
};
$scope.remaining = function() {
var count = 0;
$scope.todos.forEach(function(todo) {
count += todo.done ? 0 : 1;
});
return count;
};
$scope.archive = function() {
var oldTodos = $scope.todos;
$scope.todos = [];
oldTodos.forEach(function(todo) {
if (!todo.done) $scope.todos.push(todo);
});
};
});<!doctype html>
<html ng-app="todoApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js">
</script>
<script src="todo.js"></script>
<link rel="stylesheet" href="todo.css">
</head>angular.module('todoApp', [])angular.module defines module: application = one or more modules
module name
module dependencies
<body>
<h2>Todo</h2>
<div ng-controller="TodoListController">
...
<ul class="unstyled">
<li ng-repeat="todo in todos">
<input type="checkbox" ng-model="todo.done">
<span class="done-{{todo.done}}">{{todo.text}}</span>
</li>
</ul>angular.module('todoApp', [])
.controller('TodoListController', function($scope) {
$scope.todos = [
{text:'learn angular', done:true},
{text:'build an angular app', done:false}
];
...
});
text binding span content
text binding class name
<form ng-submit="addTodo()">
<input type="text" ng-model="todoText" size="30"
placeholder="add new todo here">
<input class="btn-primary" type="submit" value="add">
</form>angular.module('todoApp', [])
.controller('TodoListController', function($scope) {
...
$scope.addTodo = function() {
$scope.todos.push({text:$scope.todoText, done:false});
$scope.todoText = '';
};
...
}); <div ng-controller="TodoListController">
<span>{{remaining()}} of {{todos.length}} remaining</span>
[ <a href="" ng-click="archive()">archive</a> ]angular.module('todoApp', [])
.controller('TodoListController', function($scope) {
...
$scope.remaining = function() {
var count = 0;
$scope.todos.forEach(function(todo) {
count += todo.done ? 0 : 1;
});
return count;
};
$scope.archive = function() {
var oldTodos = $scope.todos;
$scope.todos = [];
oldTodos.forEach(function(todo) {
if (!todo.done) $scope.todos.push(todo);
});
};
...
});<html ng-app='myApp'>
<body ng-controller='CartController'>
<h1>Your Order</h1>
<div ng-repeat='item in items'>
<span>{{item.title}}</span>
<input ng-model='item.quantity'>
<span>{{item.price | currency}}</span>
<span>{{item.price * item.quantity | currency}}</span>
<button ng-click="remove($index)">Remove</button>
</div>
<script src="angular.js"></script>
<script src="myapp.js"></script>
</body>
</html>angular.module('myApp', []).controller('CartController', function($scope){
$scope.items = [
{title: 'Paint pots', quantity: 8, price: 3.95},
{title: 'Polka dots', quantity: 17, price: 12.95},
{title: 'Pebbles', quantity: 5, price: 6.95}
];
$scope.remove = function(index) {
$scope.items.splice(index, 1);
}
});<p>{{greeting}}</p>
<p ng-bind="greeting"></p>
$scope.greeting = "Hello there!"
---
<p>Hello there!</p>
<p>Hello {{name}}!</p>
<p ng-bind-template="Hello {{name}}!"></p>
$scope.name = "Ned Stark"
---
<p>Hello Ned Stark!</p>
While loading application:
<p ng-cloak>Hello {{name}}!</p>
<p ng-cloak>Hello {{name}} from {{city}}!</p>
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
display: none !important;
}<p>{{count * price() | currency}}</p>
<p ng-bind="count * price() | currency"></p>
<p>Hello {{name}} from {{city}}!</p>
<p>
Hello
<span ng-bind="name"></span>
from
<span ng-bind="city"></span>
!
</p>
<p ng-bind-template="Hello {{name}} from {{city}}!">
</p><a href="{{user.profile.url}}">
Link to user profile
</a>
<img src="{{user.avatar.url}}">
<a ng-href="user.profile.url">
Link to user profile
</a>
<img ng-src="user.avatar.url"><form class="form form-{{form.state}}">
...
</form>
<ul>
<li ng-class="{'active': state == 'home'}">
Home
</li>
<li ng-class="{'active': state == 'settings'}>
Settings
</li>
</ul><div ng-controller="MyCtrl">
<!-- Here we have access to MyCtrl scope -->
</div><div ng-controller="MyCtrl">
<!-- Here we have access to MyCtrl scope -->
<div ng-controller="InnerCtrl">
<!-- Here we have access to InnerCtrl scope -->
</div>
</div><body ng-app>
<!-- Here we have access to app's rootScope -->
<div ng-controller="MyCtrl">
<!-- Here we have access to MyCtrl scope -->
</div>
</body><div ng-controller="MyCtrl">
<p>Hello {{name}}!</p>
<p>You live in: {{place}}</p>
<p>Your job is: {{job}}</p>
<div ng-controller="InnerCtrl">
<p>Your name is: {{name}}</p>
<p>You live in: {{place}}</p>
<p>Your job is: {{job}}</p>
</div>
</div>
app.controller('MyCtrl', function($scope){
$scope.name = "Cercei";
$scope.place = "King's Landing";
});
app.controller('InnerCtrl', function($scope){
$scope.name = "Joffrey";
$scope.job = "King";
$scope.$parent.job = "Queen";
});<div ng-controller="MyCtrl">
<p>Hello {{name}}!</p>
<p>Name length: {{length}}</p>
<p>It's a {{message}} name!</p>
<input type="text" ng-model="name">
</div>
app.controller('MyCtrl', function($scope){
$scope.name = "Hodor";
$scope.length = $scope.name.length;
$scope.message = "short";
$scope.$watch('name', function(val){
$scope.length = val.length;
})
$scope.$watch('length', function(val){
$scope.message =
(val > 20) ? 'long' : 'short';
});
});<div>
<ul ng-show="user.interests">Interests:
<li ng-repeat="interest in user.interests">
{{interest}}
</li>
</ul>
<p ng-hide="user.interests">
No interests selected!
</p>
</div>
<div>
<video ng-if="intro.active" src="tutorial.ogg">
</video>
</div><div>
<ul ng-show="user.interests">Interests:
<li ng-repeat="interest in user.interests">
{{interest}}
</li>
</ul>
<p ng-hide="user.interests">
No interests selected!
</p>
</div>
<div>
<video ng-if="intro.active" src="tutorial.ogg">
</video>
</div>
<div ng-switch on="user.category">
<p>Your prize is:</p>
<b ng-switch-when="child">bag of candies!</b>
<b ng-switch-when="adult">bottle of beer!</b>
<b ng-switch-default>10$</b>
</div><div ng-include="sidebar.html"></div><div ng-init="votes = 0">
<button ng-click="active = true">
Activate
</button>
<button ng-click="votes = votes + 1">
Vote
</button>
<button ng-click="activate()">
Activate
</button>
</div><table>
<tr ng-repeat="person in people">
<td ng-class="{'row-odd': $odd}">Entry</td>
<td>{{person.name}}</td>
<td>{{person.city}}</td>
<td>{{person.age}}</td>
<td>
<button ng-click="notice($index)">
Send notice
</button>
</td>
</tr>
</table> <div ng-controller="MyCtrl">
<form class="form-inline">
<input ng-model="query" type="text"
placeholder="Filter by" autofocus>
</form>
<ul ng-repeat="friend in friends | filter:query | orderBy: 'name' ">
<li>{{friend.name}}</li>
</ul>
</div>ng-submit cancel default browser submit action and launch provided function for handling form processing
<form action="/user/profile" method="POST">
<input type="text" name="nick">
<textarea name="comment"></textarea>
<input type="submit value="Send">
</form>
<form ng-submit="postComment()">
<input type="text" ng-model="post.nick">
<textarea ng-model="post.comment"></textarea>
<button>Send</button>
</form>
app.controller('CommentCtrl', function($scope){
$scope.postComment = function(){
sendToServer($scope.post);
}
});ng-model works with most types of inputs:
text, email, password, radio, checkbox, textarea
<form>
Name:
<input type="text" ng-model="user.name" required /><br />
E-mail:
<input type="email" ng-model="user.email" /><br />
Gender:
<input type="radio" ng-model="user.gender" value="male" />
male
<input type="radio" ng-model="user.gender" value="female" />
female<br />
<textarea ng-model="user.description"></textarea>
<input type="submit" ng-click="update(user)" value="Save" />
</form>ng-model works also with select
ng-repeat can be used for dynamic options list
<form>
<select name="singleSelect" ng-model="data.singleSelect">
<option value="option-1">Option 1</option>
<option value="option-2">Option 2</option>
</select>
<br>
<select name="repeatSelect" id="repeatSelect" ng-model="data.repeatSelect">
<option ng-repeat="option in data.availableOptions" value="{{option.id}}">
{{option.name}}
</option>
</select>
<input type="submit" ng-click="update(user)" value="Save" />
</form>ng-model adds these classes:
<form novalidate>
Name:
<input type="text" ng-model="user.name" required>
E-mail:
<input type="email" ng-model="user.email" required>
<input type="submit" ng-click="save()" value="Save">
</form>validation adds these properties:
<form name="userForm" ng-submit="saveUser()" novalidate>
Name:
<input type="text" ng-model="user.name" required>
E-mail:
<input type="email" ng-model="user.email" required>
<input type="submit" ng-disabled="userForm.$invalid" value="Save">
</form>validation adds these properties:
<form name="userForm" ng-submit="saveUser()" novalidate>
Name:
<input type="text" ng-model="user.name" name="name" required>
E-mail:
<input type="email" ng-model="user.email" name="email" required>
<input type="submit" ng-disabled="userForm.$invalid" value="Save">
</form>basic validators:
<input
ng-model="string"
[name="string"]
[required="string"]
[ng-required="boolean"]
[ng-minlength="number"]
[ng-maxlength="number"]
[ng-pattern="string"]
[ng-change="string"]
[ng-trim="boolean"]>
...
</input><div class="form-group">
<label>Name</label>
<input type="text" name="name" class="form-control" ng-model="name" required>
<p ng-show="userForm.name.$invalid && userForm.name.$dirty" class="help-block">
You name is required.</p>
</div>
<div class="form-group">
<label>Username</label>
<input type="text" name="username" class="form-control"
ng-model="user.username" ng-minlength="3" ng-maxlength="8">
<p ng-show="userForm.username.$error.minlength" class="help-block">Username is too short.</p>
<p ng-show="userForm.username.$error.maxlength" class="help-block">Username is too long.</p>
</div>objectForm.model.$error:
object containing all model errors
key - validator, value - error message
<html ng-app="admin">
<head>
<script src="src/angular.js">
</script>
<script src="src/app.js"></script>
</head>
<body>
<h1>Admin panel</h1>
<div ng-view></div>
</body>
</html>ng-view - directive loading and switching views based on route
$routeProvider - service user for defining routes
$routeParams - service for retrieving set of route parameters
var app = angular.module('admin', []);
app.config(function($routeProvider){
$routeProvider
.when('/', {
controller: 'DashboardCtrl',
templateUrl: 'users/dashboard.html'
})
.when('/user/:id', {
controller: 'UserCtrl',
templateUrl: 'users/profile.html',
})
.otherwise({redirectTo: '/'});
});
app.controller('DashboardCtrl', function($scope){
$scope.users = gelAllUsers();
});
app.controller(
'UserCtrl', function($scope, $routeParams){
$scope.user = getUser($routeParams.id);
});
Modules - since JS have no modules system (almost true), Angular implements it's own system
Dependency Injection - it's mechanism used when dependency is required for module - it prepares and provides dependency for module
Services - modules that contains logic unrelated to views (reusable logic outside of controllers and directives)
app.config(function($routeProvider){
...
});
app.controller(
'DashboardCtrl', function($scope){
...
});
app.controller(
'UserCtrl', function($scope, $routeParams){
...
});
app.factory('Users', function() {
function create(user) { ... }
function getAll() { ... }
function find(id) { ... }
function delete(id) { ... }
return {
create: create,
getAll: getAll,
find: find,
delete: delete
}
});
app.controller('MyCtrl', function($scope, Users){
$scope.usersList = Users.getAll();
$scope.currentUser = Users.find(1);
})app.factory('github', function() {
var serviceInstance = {};
// define Github API calls
return serviceInstance;
});
app.controller('MyCtrl',
function($scope, Users, github){
$scope.usersList = Users.getAll();
$scope.currentUser = Users.find(1);
$scope.projects =
github.getProjects(currentUser.email);
})app.factory('CurrentUser', function() {
function isAuthorised() { ... }
function getCurrentUser() { ... }
function authorize() { ... }
function isAdmin() { ... }
function logout() { ... }
return {
isAuthorised: isAuthorised,
getCurrentUser: getCurrentUSer,
authorize: authorize,
isAdmin: isAdmin,
logout: logout
}
});
app.factory('audio', function($document) {
var audio = $document[0].createElement('audio');
return audio;
});
app.factory('player', function(audio) {
var player = {
playing: false,
current: null,
ready: false,
play: function(program) {
...
},
stop: function() {
...
}
};
return player;
});Asynchronous JavaScript and XML
Standard flow
Asynchronous JavaScript and XML
AJAX flow
Representational State Transfer (REST)
GET
Read a specific resource (by an identifier) or a collection of resources.
PUT
Update a specific resource (by an identifier) or a collection of resources.
DELETE
Remove/delete a specific resource by an identifier.
POST
Create a new resource. Also a catch-all verb for operations that don't fit into the other categories.
/users/12345
- collection: users
- item id: 12345
/customers/33245
/user/12/comments
/orders/8769/lineitems/1
Callbacks
function doNumbers(x, y, callback) {
var my_number =
Math.ceil(Math.random() * (x - y) + y);
callback(my_number);
}
doNumbers(5, 15, function(num) {
console.log("callback called! " + num);
});
//------------------------------------
function handleData(data) {
alert(data);
}
$.ajax({
url : 'example.com',
type: 'GET',
success : handleData
});
button.on('click' function(){
console.log('button is clicked!');
})Promises
var promise = getData()
.then(function(string) {
console.log(string)
}, function(error) {
console.error(error)
})
.finally(function() {
console.log('Finished at:', new Date())
});
var promise = getData()
.then(function(num) {
console.log(num)
return num * 2
})
.then(function(num) {
console.log(num) // = random number * 2
})$http
var promise = $http({
method: 'GET',
url: '/api/users.json'
});
promise.then(function(resp) {
// do sth with users
});
promise.success(function(...));
promise.error(function(...));
$http.get('api/user', {params: {id: '5'}})
.success(function(data, status, headers, config) {
// Do something successful.
}).error(function(data, status, headers, config) {
// Handle the error
});
var postData = {text: 'long blob of text'};
$http.post('api/user', postData, {params: {id: '5'}})
.success(function(data, status, headers, config) {
// Do something successful
}).error(function(data, status, headers, config) {
// Handle the error
});
app.controller('MyCtrl',
function($scope, $http){
$scope.users = [];
$http.get('api/user')
.success(function(data) {
$scope.users = data.users;
}).error(function() {
console.log('Cannot load users!');
});
})$http
app.factory('githubService', function($http) {
var githubUsername;
var doRequest = function(path) {
return $http({
method: 'JSONP',
url: 'https://api.github.com/users/' + githubUsername + '/' + path + '?callback=JSON_CALLBACK'
});
}
return {
events: function() { return doRequest('events'); },
setUsername: function(newUsername) { githubUsername = newUsername; }
};
});$http
app.factory('Findings', function($http) {
var base;
base = "/api/v1/findings";
return {
index: function(params) {
return $http.get(base + ".json", {
params: params
});
},
"new": function(params) {
return $http.post(base + ".json", params);
},
update: function(id) {
return $http.put(base + "/" + id + ".json");
},
single: function(id) {
return $http.get(base + "/" + id + ".json");
},
remove: function(id) {
return $http["delete"](base + "/" + id + ".json");
},
title: function(link) {
return $http.get(base + "/get_title.json", {
params: {
link: link
}
});
}
};
});app.controller('findingCtrl',
function($scope, $routeParams, Findings, Comments) {
$scope.id = $routeParams.finding_id;
Findings.single($scope.id).success(function(data) {
return $scope.finding = data;
});
$scope.saveComment = function(id, type, content) {
if (content != null) {
Comments["new"](id, type, content).then(function() {
Findings.single($scope.id).success(function(data) {
$scope.finding = data;
});
$scope.content = '';
});
}
};
});
How to use directive?
Best practices: element or attribute
app.directive('helloWorld', function() {
return {
restrict: 'AE',
replace: 'true',
template: '<h3>Hello World!!</h3>'
};
});<div>
<hello-world/>
</div>
<div>
<div hello-world></div>
</div>
-------------------------
<div>
<h3>Hello World!</h3>
</div>app.directive('helloWorld', function() {
return {
restrict: 'AE',
template: '<h3>Hello World!!</h3>'
};
});<div>
<hello-world/>
</div>
<div>
<hello-world>
<h3>Hello World!</h3>
</hello-world>
</div>
---------------------
<div>
<div hello-world></div>
</div>
<div>
<div hello-world>
<h3>Hello World!</h3>
</div>
</div>app.directive('helloWorld', function() {
return {
restrict: 'AE',
template: '<h3>{{greeting}} {{name}}{{shout()}}</h3>',
link: function(scope, element, attr) {
scope.greeting = "Hi";
scope.shout = function() {
return "!".repeat(scope.name.length);
}
}
};
});Link function gives access to:
Why using parent scope would be a bad idea?
How to solve this problem?
app.directive('helloWorld', function() {
return {
restrict: 'AE',
scope: {
greeting: '@greeting', // in this case '@'
name: '=name' },
template: '<h3>{{greeting}} {{name}}{{shout()}}</h3>',
link: function(scope, element, attr) {
//scope.greeting = "Hi";
scope.shout = function() {
return "!".repeat(scope.name.length);
}
}
};
});
<div hello-world greeting="Hi"
name="user.name"></div>
<div hello-world greeting="{{user.greeting}}"
name="user.name"></div>Passing variables to scope:
app.directive('helloWorld', function() {
return {
restrict: 'AE',
scope: {
greeting: '@greeting', // in this case '@'
name: '=name' },
template: '<h3>{{greeting}} {{name}}{{shout()}}</h3>',
link: function(scope, element, attr) {
//scope.greeting = "Hi";
scope.shout = function() {
return "!".repeat(scope.name.length);
}
}
};
});
<div hello-world greeting="Hi"
name="user.name"></div>
<div hello-world greeting="{{user.greeting}}"
name="user.name"></div>Passing variables to scope:
PS Workshops!