Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Workshop 13: AngularJS Parte II

Workshop AngularJS (2/3)
Creación de nuevas funcionalidades custom.

Presentado por ingenieros: Enrique Oriol y Héctor Canto

  • Login to see the comments

  • Be the first to like this

Workshop 13: AngularJS Parte II

  1. 1. Front End Workshops XII. AngularJS - Part 2 Enrique Oriol Bermúdez Héctor Canto
  2. 2. Overview “AngularJS lets you write client-side web applications as if you had a smarter browser”
  3. 3. Overview “AngularJS is easy” AngularJS learning curve AngularJS is amazing... and hard as hell
  4. 4. Content ● Digest Cycle ● Services ● Dependency Injection ● Routes ● Building Filters ● Building Directives
  5. 5. Digest Cycle the tech behind 2 way data binding magic
  6. 6. Digest cycle User event (ng-click) Sync work in controllers Async work in $http, $timeout and $interval scope.$apply Start from root scope Check all watchers on scope more scopes? Update UI value changed no change switch to scope and continue checking everything’s done $digest phase
  7. 7. Digest cycle What about async events? If you want to update view after receiving async event, you should force a $apply call. Don’t do it directly: use $timeout // Somewhere, an async handler var handler = function(){ $rootScope.$emit("changeContent"); }; //in your controller $rootScope.$on("changeContent", function(){ console.log("rootScope event has been fired"); $timeout(function(){ $ = "Data should change"; }); });
  8. 8. Services Where business logic lives
  9. 9. Services Services refers to injectable objects whose API is defined by the developer (not the framework) Reusable business logic, view independant
  10. 10. Services Singleton objects Once defined, it can be injected into other angular components like controllers, directives and services
  11. 11. Registering Services Module exposes 5 methods to instruct the injector how to evaluate our code var myApp = angular.module('myApp', ['']) .constant('myConstant', {}) .value('myValue', {}) .service('myService', function(){}) .factory('myService', function(){}) .provider('myService', function(){})
  12. 12. Registering Services Application life-cycle splits in 2 phases ● Configuration phase (app bootstrap) ○ No services ○ Configure and instantiate providers ● Run phase (after config) ○ No Providers interaction ○ Services start being created
  13. 13. ● For simple values of any type ● Do not accept DI / being configured ● Can be injected into the config function myApp.constant('SERVERS',{ DEVELOPMENT: "http://localhost:8080/app", PRODUCTION:""}); Constant myApp.config(function(SERVERS){ console.log(SERVERS.PRODUCTION); });{ console.log(SERVERS.DEVELOPMENT); }) Definition CONFIG USAGE RUN USAGE
  14. 14. ● Simple objects or primitives ● Do not accept DI / being configured myApp.value('randomize',function(){ return Math.floor(Math.random()*10000);}) myApp.value('token','a1234567890'); myApp.value('User',{'id': 'someId'}) Value, User){ var num = randomize(); = num; }); Definition USAGE
  15. 15. ● Constructor function that will be instantiated (internally invokes it with new) ● Cannot being configured ● Arguments represents DEPENDENCIES to be injected myApp.service('AuthBearer', ['token', function(token) { this.authValue = "bearer " + token; }]); Service{ console.log(AuthBearer.authValue); }) Definition USAGE myApp.value('token','a1234567890'); TOKEN is INJECTED!!!
  16. 16. ● Uses DI, No config ● Allows service initialization myApp.factory('apiToken', ['$window', 'clientId', function apiTokenFactory($window, clientId) { var encrypt = function(data1, data2) { // NSA-proof encryption algorithm: return (data1 + ':' + data2).toUpperCase(); }; var secret = $window.localStorage.getItem('myApp.secret'); var apiToken = encrypt(clientId, secret); return apiToken; }]); Factory { console.log(apiToken); }) Definition USAGE
  17. 17. ● Uses DI ● Exposes API for service config before app starts (config phase) ● $get method is a factory function, that creates our service myApp.provider('logger', function(){ var logToConsole = false; this.enableConsole = function(flag){ logToConsole = flag; }; this.$get = function(){ return { debug: function(msg){ if(logToConsole){ console.log(msg);} } }; }; }) Provider Definition
  18. 18. Provider myApp.config(function(loggerProvider){ loggerProvider.enableConsole(true); }) CONFIGURATION{ logger.debug('Hello world'); }) USAGE myApp.provider('logger', function(){ var logToConsole = false; this.enableConsole = function(flag){ logToConsole = flag; }; this.$get = function(){ return { debug: function(msg){ if(logToConsole){ console.log(msg);} } }; }; }) REMEMBER
  19. 19. myApp.provider('logger', function(){ var logToConsole = false; this.enableConsole = function(flag){ logToConsole = flag; }; this.$get = function(){ return { debug: function(msg){ if(logToConsole){ console.log(msg);} } }; }; }); Provider shorthands Provider Factory Service
  20. 20. Dependency Injection Pervasive pattern along angular
  21. 21. Dependency Injection Software design pattern that deals with how components get hold of their dependencies
  22. 22. Dependency Injection The Angular injector subsystem is in charge of creating components, resolving their dependencies, and providing them to other components as requested.
  23. 23. Dependency Injection The key players are the provide & injector services The magic behind
  24. 24. Dependency Injection We register our code on the injector with the provide service$provide The magic behind
  25. 25. Dependency Injection We must provide a key as the first argument The magic behind
  26. 26. Dependency Injection The injector keeps our code in an internal object called providerCache The magic behind
  27. 27. Dependency Injection We use the injector to retrieve object instances$injector The magic behind
  28. 28. Dependency Injection First time we inject a service, the injector evaluates the code and stores the result in an instanceCache object The magic behind
  29. 29. Dependency Injection When injecting a service, injector always look first into instanceCache The magic behind
  30. 30. Dependency Injection That’s why our services are singletons The magic behind
  31. 31. Dependency Injection Components, controllers and run accept any service DI (not providers) config can be injected with provider and constant components How to use it
  32. 32. Dependency Injection 3 ways to use DI: Implicit Annotation $inject Property Annotation Inline Array Annotation How to use it
  33. 33. Dependency Injection Implicit Annotation How to use it myApp.controller('MyCtrl', function($scope, logger) { // ... }); The Simplest way If we minify our code, service names as arguments will be renamed, and app will break.var MyController = function($scope, logger) { // ... } myApp.controller('MyCtrl', MyController]);
  34. 34. Dependency Injection $inject property Annotation How to use it var MyController = function($scope, logger) { // ... } MyController.$inject = ['$scope', 'logger']; myApp.controller('MyCtrl', MyController); The Long way Order of parameters must MATCH
  35. 35. Dependency Injection Inline Array Annotation How to use it myApp.controller('MyCtrl', ['$scope', 'logger', function($scope, logger) { // ... }]); The prefered way var MyController = function($scope, logger) { // ... } myApp.controller('MyCtrl', ['$scope', 'logger', MyController]); Order of parameters must MATCH
  36. 36. Routes Navigating Through Views
  37. 37. Routes 2 common routing libs ● ngRoute$route ○ Official ○ Separated in ngRoute module ○ Only one navigation view per application ● ui-router ○ Community chosen ○ More powerful ○ More flexible
  38. 38. ui-router based on states concept can use routes other behaviours
  39. 39. ui-router What is a ‘state’? A place in the app, in terms of UI and navigation Describes how the UI looks like and what does at that place States are bound to named, nested and parallel views
  40. 40. ui-router Installation $ bower install angular-ui-router <script src="angular.js"></script> <script src="angular-ui-router.js"></script> angular.module('myApp', ['ui.router']); Get Package Include Script Import Module
  41. 41. ui-router Simple State angular.module('myApp', ['ui.router']) .config(function($stateProvider){ $stateProvider .state('home', { url: '/home.html', templateUrl: 'views/home.html' }); }); <!-- index.html --> <head> <!--...stuff...--> </head> <body ng-app> <!--...stuff...--> <ui-view></ui-view> </body> Defining State Directive ui-view
  42. 42. ui-router $stateProvider $state is a service defined with provider method that gives us $stateProvider to prepare $state at config phase $state is the ui-router service to handle states$state
  43. 43. ui-router Navigation <body> <div ui-sref='home'>Navigate!</div> <ui-view></ui-view> </body> <body ng-controller="Ctrl"> <div ng-click="navigate()">Navigate!</div> <ui-view></ui-view> </body> NAV THROUGH VIEW NAV THROUGH CONTROLLER myApp.controller('Ctrl', function($scope, $state){ $scope.navigate = function(){ $state.go('home'); } }) link href also works, but AngularJS introduces #: <a href='#/home'></a>
  44. 44. ui-router Some state options .config(function($stateProvider){ $stateProvider .state('home', { url: '/home.html', templateUrl: 'views/home.html', controller: 'HomeCtrl', data:{ level: 'PRO' } }); }); .controller('HomeCtrl', function($scope, $state){ $scope.message = "Hi world!, you belong to " + $ + " level"; })
  45. 45. ui-router Parameters .config(function($stateProvider){ $stateProvider .state('home', { url: '/home/:username', templateUrl: 'views/home.html', controller: 'HomeCtrl' }); }); .controller('HomeCtrl', function($scope, $stateParams){ $scope.message = "Hi " + $stateParams.username; }) .controller('Ctrl', function($scope, $state){ $scope.navigate = function(){ $state.go('home', {username: "Marqués"}); } }) <button ui-sref="home({username:'Bob'})"> Navigate using ui-sref </button>
  46. 46. ui-router .config(function($stateProvider){ $stateProvider .state('home', { url: '/home/:username', templateUrl: 'views/home.html', controller: 'HomeCtrl', data:{ level: 'PRO'} }) .state('home.profile', { url: '/profile', templateUrl: 'views/profile.html', controller: 'ProfileCtrl' }) }); Nested views .controller('HomeCtrl', function($scope, $state, $stateParams){ $scope.homeMsg = "Home, sweet home " + $stateParams.username; }) .controller('ProfileCtrl', function($scope, $state, $stateParams){ $scope.user = { name: $stateParams.username, level: $ }; }) <button ui-sref="home.profile({username:'Bob'})"> </button>
  47. 47. ui-router .config(function($stateProvider){ $stateProvider .state('home', { views:{ "": { template: '<ui-view></ui-view>' }, "header": { templateUrl: 'views/header.html', controller: 'HeaderCtrl' }, "footer": { template:"<div class='vCentered'>All rights reserved</div>" } } }) }) Named views <body ng-controller="Ctrl"> <div class="container"> <ui-view></ui-view> <div ui-view="header"></div> <div ui-view="footer"></div> <div> </body> ui-view directive can be used as Element or as Attribute
  48. 48. ui-router .config(function($stateProvider, $urlRouterProvider){ $stateProvider.state(...) $urlRouterProvider.otherwise('#/home') //this is a URL }) Redirections .run(function($state){ $state.transitionTo('home); }); Always that Url is unknown At Launch
  49. 49. use state property abstract:true abstract states cannot be directly activated abstract states can have controller Useful for nested views ui-router Abstract states
  50. 50. ● abstract states ● nested states ● named states ui-router Let’s see a full example with:
  51. 51. ui-router State resolve and callbacks .state('home', { resolve: {user: function(){}}, //where function returns a promise onEnter: function(user){}, onExit: function(user){} });
  52. 52. ui-router state requested $stateChangeStart $stateChangeSuccess ui-view kicks in $viewContentLoaded Done State Life Cycle & Events $stateChangeError $stateNotFound onload function
  53. 53. Filters — AND $Filter.(‘filter’) —
  54. 54. Filters Pre-defined filters: currency, number, date, lowercase, orderBy, filter … ● We can apply several filters to the same expression Format: {{ expression | filter:argument1:argument2 | filter2 … }} Some examples: {{ 5 | currency: ”€”, 2}} >> €5.00 {{ 5 | currency: ””, 2}} + “ €“ >> 5.00 € {{ “hello” | uppercase }} >> HELLO
  55. 55. Custom Filter app.filter('filtername', function() { return function(input) { return input + ‘some text’; }; DOM filter {{ input_expression | filtername }} Controller filter $filter(‘filtername’)(input_expression, argument);
  56. 56. How filters work ● Every binded expression will have a $watcher. ○ So don’t spare on filters if they improve your life. ● Watchers are checked every digest loop, but only run on changes. ○ Filters take as much time as the function they run. ● Optimization ○ Use one-way binding (::value) ○ If something won’t change, pre-process it, don’t filter it. ○ Avoid DOM filters when possible ○ Beware of dependencies, don’t introduce state. ○ Preferably with strings
  57. 57. Stateful Filters Typical case: {{ 'TRANSLATIONID' | translate }} ● The ID never changes but the language does. ● Used on ng-translate. angular.module('myApp', []) .filter('translate', ['translationService', function (translationService) { function translate(input) { chain_translated += translationService.getChain(input); return chain_translated; } translate.$stateful = true; return translate; }]);
  58. 58. Directives — DOM Manipulation —
  59. 59. Directives Main purpose: Directives are markers on a DOM element that tell Angular’s HTML “compiler” to attach a certain behaviour to it (via event listeners). Structure ● Snake and camelCase naming format ● Restrict roles ● Template vs. TemplateURL ● Controller and controllerAs ● Scope isolation ● Functions
  60. 60. By intuition you may think that a directive is a component of the template. That being correct, it is more than that. Directives can : ● add or modify behaviour of elements ● add real-time dynamism to elements >> two way data binding ● add interactivity with the user ● modify or complement other directives ● add a complete element ● provide code reutilization, for instance: animations, styles ... ● connect elements data and behaviour Directives
  61. 61. Custom Directives: Naming format Directives are meant to be part of the template so their naming format are restricted to HTML syntax. Automatically, camelCase names are understood on the template as Snake names, see the example below: app.directive(customDirective, function() { return { } }); <custom-directive></custom directive> <x_custom_directive></x_custom_directive> <data:custom:directive></data:custom:directive>
  62. 62. Custom Directives: Roles Directives can play different roles in the template: ● Element, attribute, class or comment even. Restrictions should be applied. ● Element and attribute allow parameters. ● More intuitive to use element, but attribute helps separating CSS. app.directive(CustomDirective, function() { return { restrict: 'EACM', scope: {}, template: '<div class="sparkline"><h4>Hello world</h4></div>', controller: function (){}, controllerAs: ‘ctrl1’, link: function() {}, } }); WARNING: Compatibility issues with C and M.
  63. 63. template vs. templateURL They are equivalent but templateURL is recommended. ● templateURL points to a file template (with path) ○ We can use a function previously defined ○ We can use import mechanisms from requireJS or ES6 ● template is the template inline template: '<div class="sparkline"><h4>Hello world</h4></div>', templateURL: 'path/to/template.html', templateURL: tpl,
  64. 64. Custom directives: controller Usually a directive is bound to a controller and this is achieved by defining or passing the controller to the directive. controller: function() {return;} The controller is run after the template is compiled but before the DOM is completed and the scope linked between directives. So, variables has not been replaced and data-binding has not been performed. DON’T MANIPULATE THE DOM HERE The controller is meant to set the data necessary for the directive and interact with the rest of the application. Think of it as the API for the directive.
  65. 65. Custom directives: controllerAs ControllerAs creates a variable in the directive’s scope that will hold the Controller’s scope: ControllerAs: ‘ctrl1’, $scope.ctrl1.something ● Recommended for confusing namespaces ● Avoids overlapping of variables with the same name ● Identifies levels of inheritance ● Using this becomes safer, but you might be using $scope already.
  66. 66. @ Text binding passes string values and does one way binding. Allow interpolation as in the example above. & One way or once: changes on the directive will not affect the parent scope. Think of it as a getter. Can be used to call external functions = Two way passes objects and changes affect to both directive and higher scopes (all if not limited). It is the more magical one but it comes with a cost. Custom directives: Binding styles angular.module("myApp",[]) .directive("myDirective", function () { return { restrict: "A", scope: { text: "@myText", oneWayBind: "&myOneWayBind", twoWayBind: "=myTwoWayBind", name: "=" } }; }).controller("myController", function ($scope) { $ = {name: "zwerty"}; $ = "qwerty"; $ = "name"; }); <div ng-bind="myController"> <div my-directive my-text="hello {{ bar }}" my-two-way-bind="foo" my-one-way-bind="bar"> </div> </div> PAY ATENTION TO {{bar }} in my-text
  67. 67. More on binding styles ● ng-bind is one way. ● ng-model is two way. ● {{ var }} is similar to a one way binding, but it is dirty checked every digest cycle. ○ Using {{::var}} we limit the checking to the first time (once)is one way. ● So {{ var }} is potentially slower than ng-model because the first is interpreted every digest cycle.
  68. 68. By default a directive inherits the scope of his parent. For example an ng- controller: div ng-controller="ParentController"> ParentController: <input type="text" ng-model="foo" /> <custom-directive></custom-directive> </div> Inheritance goes all the way to the upper level. And also affects siblings. Custom directives: Scope inheritance
  69. 69. If we initialize the property scope in the directive’s definition we achieve an isolated scope (at least partially): scope: {}, scope: true, scope: {foo: "..."} Isolation is partial, but controlled, by the data-binding. Nevertheless, inheritance is still happening as we can see in this example: Custom directives: Isolated scope
  70. 70. angular.module('directivesModule').directive('isolatedScopeWithController', function () { return { restrict: 'EA', scope: { datasource: '=', add: '&', }, controller: function ($scope) { ... $scope.addItem = function () { var name = 'New Item Added by Directive'; $scope.add( )(name); $scope.items.push({ name: name }); }; }, template: '<button ng-click="addItem()">Change Data</button><ul> <li ng-repeat="element in items">{{ }}</li></ul>' }; }); Custom directives: Isolated scope II <div isolated-scope-with-controller datasource="items" add="addCostumer"> </div>
  71. 71. There are 3 types of functions, by order of execution: ○ compile, controller and link ● Compile happens once, before the template is compiled. ● The rest of functions is run once for each time the directive is used ■ For example in a ng-repeat of 4 elements, 4 loops ○ Controller initialize the scope. ○ Link happens when the linking is being made, by default after. ○ We can divide link into two, pre-link and post-link ■ Pre-link happens before the element is linked to the scope ■ Post-link happens just after, when the element affected is on the DOM. ● This is the most usual and potentially safest Custom directives: functions angular-directives/
  72. 72. Custom directives: link, prelink, postlink ● There are 4 arguments available for these functions (in this order) ○ scope, elements, attributes and controllers ● You can access the DOM, you have the element. ● By default use link directly, which is equivalent to post-link alone. ● Remember, if possible provide values as soon as you can. ○ Don’t wait to post-link, do it in the controller or in compile ● [post-]link is the View part where you have everything in place and you do the last adjustments and decisions regarding the DOM.
  73. 73. Custom directives: link, prelink, postlink var app = angular.module('app', []); app.directive('dad', function () { return { restrict: 'EA', template: '<div class="dad">{{greeting}}{{name}}'+ '<son></son>'+ '</div>', link: { pre: function(scope,elem,attr){ = 'Paul'; scope.greeting = 'Hey, I am '; } } }; }) app.directive('son', function () { return { restrict: 'EA', template: '<div class="son">{{sonSays}}</div>', link: function(scope,elem,attr){ scope.sonSays = 'Hey, I am David, and my dad is '+; } }; }); <div ng-app="app"> <dad></dad> </div> Hey, I am Paul Hey, I am David, and my dad is Paul
  74. 74. Custom directives: post-link, ● It is safe to manipulate the DOM in post-link as the element is already in the DOM. ● It is possible to access the scope ● All child directives are linked so it’s safe to access them ○ their scope and the elements they affect. ● It is safe to attach events handlers to elements.
  75. 75. Custom directives: pre-link, ● Use of pre-link is scarce, ○ A child needs data from its parent ● Safe to attach an event to the DOM element ○ Not safe to access DOM elements from child directives ● The scope is not linked yet.
  76. 76. Custom directives: compile ● In this phase AngularJS manipulates the DOM of the HTML template ● Each directive has a chance to do some processing for all and each DOM nodes it appears in. ● The scope is not attached yet. ● The template is still bare, without binding nor substitutions.
  77. 77. THANKS FOR YOUR ATTENTION Leave your questions on the comments section