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

"Angular.js Concepts in Depth" by Aleksandar Simović

Embed Size (px)

Citation preview

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)