Angular overview
Why MVC
Unobtrusive JavaScript
$('.main').text('Main paragraph');
$('.main').on('click', function() {console.log('I am clicked')});
HTML
JavaScript
<p class="main"></p>
HTML
<p class="main">Main paragraph</p>
Problem
JS and HTML are not really separated:
you can’t change a line of markup without checking every single line of JavaScript to assure you’re not breaking a selector.
Two-way data binding
$scope.content = "Main paragraph";
$scope.processClick = function() {console.log('I am clicked')};
HTML
JavaScript
<p class="main" ng-bind="content" ng-click="processClick()"></p>
When run, HTML becomes like this
<p class="main" ng-bind="content" ng-click="processClick()">Main paragraph</p>
Main user visible components
Main implementation components
- $injector (dependency injection)
- $scope (dirty checking)
- $compile (data binding)
Module
Why we need modules?
- is a container for directives, controllers, and factories/services and also for the config and run blocks
- defines the loading order of the above mentioned components
How we define modules?
// define new dependent module `designer`
angular.module('designer', []);
// define new module `main` and its dependency
angular.module('main', ['designer']);
Factories/Services
Creating a service with module
angular.module('main', []).service('post', function($http) {
var root = 'http://jsonplaceholder.typicode.com';
this.getPosts = function() {
return $http.get(root + '/posts/1');
};
});
angular.module('main', []).factory('post', function($http) {
var root = 'http://jsonplaceholder.typicode.com';
return {
getPosts : function() {
return $http.get(root + '/posts/1');
}
}
});
Defining service as a `service`
Defining service as a `factory`
$injector service
angular.module('main', []).service('post', function($injector) {
function Post($http) {
var root = 'http://jsonplaceholder.typicode.com';
this.getPosts = function() {
return $http.get(root + '/posts/1');
};
}
return $injector.instantiate(Post);
})
Defining service as a `service`
Defining service as a `factory`
angular.module('main', []).service('post', function($injector) {
function Post($http) {
var root = 'http://jsonplaceholder.typicode.com';
return {
getPosts: function() {
return $http.get(root + '/posts/1');
}
}
}
return $injector.invoke(Post);
})
Scope
Dirty checking
var scope = {
itemsCount: 5,
showInvalid: true
}
var watchers = [];
function addWatcher(property, object, callback) {
var previous;
watchers.push(function watcher() {
if (object[property] !== previous) {
callback();
previous = object[property];
}
});
}
function digest() {
console.log('calling digest');
watchers.forEach(function(watcher) {
watcher();
});
}
var scope = {
itemsCount: 5,
showInvalid: true
}
addWatcher('itemsCount', scope, function() {console.log('itemsCount changed')});
digest(); // calling digest, itemsCount changed, showInvalid changed
digest(); // calling digest
scope.itemsCount = 10;
digest(); // calling digest, itemsCount changed
Dirty checking (native API)
angular.module('main', []).service('scopes', function($rootScope) {
var scope = $rootScope.$new();
setTimeout(function() {
scope.$watch('itemsCount', function() {
console.log('itemsCount changed');
});
scope.$digest(); // itemsCount changed
scope.$digest(); //
scope.itemsCount = 10;
scope.$digest(); // itemsCount changed
});
});
Scope hierarchy
angular.module('main', []).service('scopes', function($rootScope) {
var scope = $rootScope.$new();
Object.getPrototypeOf(scope) === $rootScope; // true
scope.$parent === $rootScope; // true
});
Directives
Creating directives
angular.module('main').directive('showPostTitle', function(post) {
return {
compile: function($element) {
var span = '<span>I am child span</span>';
$element.append(span);
return function($scope, $element) {
post.getPosts().then(function(data) {
$element.find('span').text(data.data.title);
});
}
}
}
})
<p class="main" show-post-title></p>
Initial HTML
<p show-post-title=""><span>sunt aut facere</span></p>
Compiled and linked HTML
$compile service
angular.module('main').directive('addClickableChild', function($compile) {
return function($scope, $element) {
var scope = $scope.$new();
scope.content = 'I am span content';
scope.processClick = function() {console.log('I am clicked')};
var span = '<span class="clickable-child" ng-click="processClick()" ng-bind="content"></span>';
var linked = $compile(span)(scope);
$element.append(linked);
}
})
<p add-clickable-child></p>
Initial HTML
<p add-clickable-child="">
<span class="clickable-child ng-binding ng-scope"
ng-click="processClick()"
ng-bind="content">
I am span content
</span>
</p>
Compiled and linked HTML
Controller
Data preparation
angular.module('main').directive('showPostTitle', function() {
return {
controller: function($scope, post) {
post.getPosts().then(function(data) {
$scope.posts = data.data.title;
});
},
compile: function($element) {
var span = '<span>I am child span</span>';
$element.append(span);
return function($scope, $element) {
$scope.$watch('posts', function(posts) {
if (posts) {
$element.find('span').text(posts);
}
});
}
}
}
})
Angular overview
By maximk
Angular overview
- 593