"angular.js concepts in depth" by aleksandar simović

37
Angular.js Concepts in Depth (we need to go deeper)

Upload: js-belgrade

Post on 15-Jul-2015

468 views

Category:

Software


2 download

TRANSCRIPT

Angular.js Concepts in Depth(we need to go deeper)

Brief overview

Quick intro (~2 min)

Core concepts:- Modules- DI- Controllers- Scopes- Views- Directives- Templates- Filters- Providers

Change detection

Note: (lns are based on Angular 1.4.0-rc.0)

quick intro(in case living under a rock)

- “JAVA script” client side framework (they call it like that when they contact you from an HR agency)

- Imposes MVW architecture- Component based- DI

module

- Logical containers- Module -> [controllers, filters, directives, services, factories, animations, configs]

Example:

angular.module('yourApp', ['yourDependency']);

its phases - or blocks:- config

(define your app configuration, e.g. routes, only providers & constants)

- run (similar to a main method, not needed but sometimes useful, only instances & constants)

(lns 1839 - 2150)

DI

- each app has one $injector- $injector can instantiate types, invoke

methods, load modules- instance cache + instance factory- credited with making all providers singletons- $injector.get()

-> if inCache() return from cache

-> else instantiate

a small DI usage example :yourApp.controller('yourCtrl', function($scope) {});

controller

- more like view models, less like controllers- controller ~ view relation: 1-1- can be used in relation 1-m (not the usual practice)- each controller has its own scope and view which

contains what is shown - created by ~ $controllerProvider

(lns 8645 - 8791)

scopes

- objects containing view related functions and properties- each controller has one- app has one “parent” scope ~ $rootScope- children can have their own children

views

At the beginning (0.x ~ 1.x) there were only classic, because the ng team thought directives could be used as composite views with state- classic views: ng-route- kinda composite: ng-include- composite views: ui-router

templates

~ an HTML fragment ~ partial view

- mostly used by directives

expressions

- code placed in “{{ }}” handlebars represent expressionsexample:

<div>{{ 3+5 }}</div>- before rendering the actual template, its expressions

are compiled by $interpolate service - detrimental to performance- always check their performance with batarang- one time binding “::” (!= one-way data binding)

(lns 10485 - 10584)

directives

- composable components- can have their own scope- they are not providers, as they are more of an extension

to the DOM elements, but they do have their $compileProvider (lns 5924 - 8518)

- can have its own controller (one of the reasons why in the first Angular versions there was no need for composite view)

(lns 18928 - 27672)

DDOyourModule.directive('directiveName', function factory(injectables) { var directiveDefinitionObject = { priority: 0, template: '<div></div>', // or // function(tElement, tAttrs) { ... }, // or // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... }, transclude: false, restrict: 'A', replace: true, templateNamespace: 'html', scope: false, controller: function($scope, $element, $attrs, $transclude, otherInjectables) { /**...*/ }, controllerAs: 'stringIdentifier', bindToController: false, require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'], compile: function compile(tElement, tAttrs, transclude) { return { pre: function preLink(scope, iElement, iAttrs, controller) { /**...*/ }, post: function postLink(scope, iElement, iAttrs, controller) { /**...*/ } }; // or // return function postLink( ... ) { ... } } // or // link: { // pre: function preLink(scope, iElement, iAttrs, controller) { ... }, // post: function postLink(scope, iElement, iAttrs, controller) { ... } // } // or // link: function postLink( ... ) { ... } }; return directiveDefinitionObject;});

directive intrinsics

phases- compile

- preLink- postLink

- link

directive source example

/*** @question* Guess which element does this native directive extend?*/var htmlAnchorDirective = valueFn({ restrict: 'E', compile: function(element, attr) { if (!attr.href && !attr.xlinkHref) { return function(scope, element) { // If the linked element is not an anchor tag anymore, do nothing if (element[0].nodeName.toLowerCase() !== 'a') return;

// SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute. var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ? 'xlink:href' : 'href'; element.on('click', function(event) { // if we have no href url, then don't navigate anywhere. if (!element.attr(href)) { event.preventDefault(); } }); }; } }});

directives

most usable ones:- model- event (ng-click, ng-mouseover...)- value- bind- class- include- repeat- show- switch

the main list is within lns 18928 - 27672

filters

- think of it as a formatter- an ng service used for formatting data to the user- example

{{ expression | filter_name[:parameter_value] ... ] }}

- when registering them, Angular automatically adds “Filter” postfix to them, in order not to mix them with other services

- all filters are handled by their own provider ~ $FilterProvider

(lns 17663 - 18926)

filters

native filter list: - currency- date- filter- json- limitTo- lowercase- number- orderBy- uppercase

providers

- referred to as “services” (op term)- Represent the state of your app- List of providers:

providerconstantfactoryservicedecoratorvalue

(lns 4170 - 4402)

provider

- Configurable factory- Meaning it has configuration options and a creation

function ($get)- Can be used during the config phase- // angular.provider('providerName');

provider source

function provider(name, provider_) { assertNotHasOwnProperty(name, 'service'); if (isFunction(provider_) || isArray(provider_)) { provider_ = providerInjector.instantiate(provider_); } if (!provider_.$get) { throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name); } return providerCache[name + providerSuffix] = provider_;}

provider examplessomeModule.provider('providerName', function (){

var trackingUrl = '/track';// A provider method for configuring where the tracked events should been savedthis.setTrackingUrl = function(url) { trackingUrl = url;};

// The service factory functionthis.$get = ['$http', function($http) { var trackedEvents = {}; return {

// Call this to track an event event: function(event) {

var count = trackedEvents[event] || 0; count += 1; trackedEvents[event] = count; return count;

}, // Call this to save the tracked events to the trackingUrl save: function() {

$http.post(trackingUrl, trackedEvents); } };}];

});

factory

- well known- most widely used- private functions- provider with a $get function- // angular.factory('someFactory', factoryObject)

factory source

function factory(name, factoryFn, enforce) { return provider(name, { $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn });}

function enforceReturnValue(name, factory) { return function enforcedReturnValue() { var result = instanceInjector.invoke(factory, this); if (isUndefined(result)) { throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name); } return result; };}

factory examples

someModule.factory('ping', ['$http', function($http) { return {

ping: function { return $http.send('/ping'); };}]);

someModule.controller('Ctrl', ['ping', function(ping) { ping();}]);

someModule.factory('ping', ['$http', function($http) { return function ping() { return $http.send('/ping'); };}]);

someModule.controller('Ctrl', ['ping', function(ping) { ping();}]);

constant- we all know what constant means- can’t be decorated (not shit, Sherlock)- injectable during config phase- Example: angular.constant('someConstantName', constantValue)

constant source

function constant(name, value) { assertNotHasOwnProperty(name, 'constant'); providerCache[name] = value; instanceCache[name] = value;}

constant – examples

someModule.constant('SHARD_HEIGHT', 306);

someModule.constant('MY_COLOURS', ['red', 'blue', 'grey']);

value

- can not be injected in the config phase- represents an angular variable that can be injected and used

throughout your providers, directives, controllers

example:angular.value('someValue', actualValue)

value source

function value(name, val) {return factory(name, valueFn(val), false);

}

service

- known but not so widespread- injectable constructor

example:angular.service('ServiceName', serviceObj);

service source

function service(name, constructor) { return factory(name, ['$injector', function($injector) { return $injector.instantiate(constructor); }]);}

service examplesvar ServiceName = function($http) { this.$http = $http;};

ServiceName.$inject = ['$http'];

ServiceName.prototype.send = function() { return this.$http.get('/some-http-address');};$provide.service('ServiceName', ServiceName);

angular.service('ServiceName', function($http){this.$http = $http;this.send = function() {

return this.$http.get('/some-http-address');};

});

decorator

- Service instantiation interceptor- Behavior override- Modify / encapsulate other providers- Can decorate every provider, except constant- Less known, barely used- why?- angular-mocks uses it to add flush() to $timeout

angular.decorator('someDecorator', decoratorObj);

decorator source

function decorator(serviceName, decorFn) { var origProvider = providerInjector.get(serviceName + providerSuffix), orig$get = origProvider.$get;

origProvider.$get = function() { var origInstance = instanceInjector.invoke(orig$get, origProvider); return instanceInjector.invoke(decorFn, null, {$delegate: origInstance}); };}

decorator example

/** * @description * * Here we decorate the ns.$log service to convert warnings to errors */

angular.decorator('$log', ['$delegate', function ($delegate) {delegate.warn = delegate.error;return delegate;

}]);

Change detection

- dirty checking- consists of running equality checks over all

of the data that the view depends on

Questions(answers not promised)