The Ultimate Introduction to AngularJS
Jacopo Nardiello Padawan Programmer Twitter: @jnardiello
Practicing the force at
What Angular is NOT
“AngularJS is not jQuery” What Angular is NOT
Framework != Library
“A framework embodies some abstract design, with more behavior built in.” ! - M. Fowler
MVC MVVMvs
What is Angular Superheroic JavaScript MVW Framework
What is Angular Superheroic JavaScript MVW Framework Model
What is Angular Superheroic JavaScript MVW Framework View Model
What is Angular Superheroic JavaScript MVW Framework View Model Whatever (works for you)
Zen of Angular
#1 “It is a very good idea to decouple DOM manipulation from app logic.”
#2 “It is a really, really good idea to regard app testing as equal in importance to app writing”
#3 “It is an excellent idea to decouple the client side of an app from the server side”
Elements of an Angular App
Bootstrapping an App <body ng-app=“car">
JS bootstrap code angular.module('car', [ 'car.service', 'car.directive', ‘car.controller’ ])
JS bootstrap code angular.module('car', [ 'car.service', 'car.directive', ‘car.controller’ ])
JS bootstrap code angular.module('car', [ 'car.service', 'car.directive', ‘car.controller’ ])
JS bootstrap code angular.module('car', [ 'car.service', 'car.directive', ‘car.controller’ ])
Angular is modular angular.module('car.service', […]) angular.module(‘car.directives', […])
Extending the DOM Angular extends DOM behavior using Directives
Directives angular.module('greetApp', []) .directive(‘greetMe’, function() { return { template: ‘<h1>Hello</h1>’ } })
angular.module('greetApp', []) .directive(‘greetMe’, function() { return { template: ‘<h1>Hello</h1>’ } }) Directives
js html <div greet-me></div> angular.module('greetApp', []) .directive(‘greetMe’, function() { return { template: ‘<h1>Hello</h1>’ } }) Directives
Adding logic to directives .directive('myCoffeeMachine', [ ‘$interval’, ‘water’, ‘pump’, function($interval, dateFilter) { return { restrict: 'AE', link: function(scope, element, attrs) { coffee = $interval(function() { prepareCoffee(); // update DOM }, n0000); } }]);
Adding logic to directives .directive('myCoffeeMachine', [ ‘$interval’, ‘water’, ‘pump’, function($interval, dateFilter) { return { restrict: ‘AE', link: function(scope, element, attrs) { coffee = $interval(function() { prepareCoffee(); // update DOM }, n0000); } }]);
Adding logic to directives .directive('myCoffeeMachine', [ ‘$interval’, ‘water’, ‘pump’, function($interval, dateFilter) { return { restrict: 'AE', link: function(scope, element, attrs) { coffee = $interval(function() { prepareCoffee(); }, n0000); } }]);
Reusable element .directive('myCoffeeMachine', [ ‘$interval’, ‘water’, ‘pump’, function($interval, dateFilter) { return { restrict: 'AE', link: function(scope, element, attrs) { coffee = $interval(function() { prepareCoffee(); // update DOM }, n0000); } }]); <my-coffee-machine></..>
Controllers “A Controller is a JavaScript constructor function that is used to augment the Angular Scope”
Controllers “A Controller is a JavaScript constructor function that is used to augment the Angular Scope”
A step back: Scopes Scope ~ Model ~ Current state
A step back: Scopes Scope ~ Model ~ Current state Scopes are objects organized hierarchically, aimed to mimic the DOM structure
A step back: Scopes Each module instantiate a rootScope object Scope ~ Model ~ Current state Scopes are objects organized hierarchically, aimed to mimic the DOM structure
A step back: Scopes
Controllers var myApp = angular.module('myApp',[]); ! myApp.controller('GreetingController', [ '$scope', function($scope) { $scope.greeting = 'Hola!'; }]); js
Controllers var myApp = angular.module('myApp',[]); ! myApp.controller('GreetingController', [ '$scope', function($scope) { $scope.greeting = 'Hola!'; }]); <div ng-controller="GreetingController"> js html
Angular automagically keeps in sync the model inside controllers with views Ultimate Data Binding
myApp.controller('GreetingController', [ '$scope', function($scope) { $scope.greeting = 'Hola!'; }]); <div ng-controller="GreetingController"> {{ greeting }} </div> Ultimate Data Binding js html
Behavior everywhere (and shared resources) What if you want to declare a class, an object or a function and have it available everywhere?
Behavior everywhere (and shared resources) Factories
Behavior everywhere (and shared resources) Factories Services
Factory Example .factory(‘addOne', function($window) { var sum = 0 return function(sum) { sum++ $window.alert(sum) } })
.factory(‘addOne', function($window) { var sum = 0 return function(sum) { sum++ $window.alert(sum) } }) Factory Example
Behavior everywhere (and shared resources) Factories Services returned value of function instance
Mounting all the pieces
Testing Angular
Misko Hevery “Agile Coach at Google where he is responsible for coaching Googlers to maintain the high level of automated testing culture” - misko.hevery.com/about/
Misko Hevery +
“Angular is written with testability in mind” - Angular Doc
Why is Angular easily testable?
Dependency Injection
DI As a Pattern Framework
DI as Pattern function Car() { var wheel = new Wheel(); var engine = Engine.getInstance(); var door = app.get(‘Door’); ! this.move = function() { engine.on(); wheel.rotate(); door.open(); } }
DI as Pattern function Car() { var wheel = new Wheel(); var engine = Engine.getInstance(); var door = app.get(‘Door’); ! this.move = function() { engine.on(); wheel.rotate(); door.open(); } }
DI as Pattern function Car(wheel, engine, door) { this.move = function() { engine.on(); wheel.rotate(); door.open(); } }
The problem function main() { var fuel = new Fuel(); var electricity = new Electricity(); var engine = new Engine(fuel); var door = new Door(Electricity); var wheel = new Wheel(); var car = new Car(wheel, engine, door); car.move(); }
The problem function main() { var fuel = new Fuel(); var electricity = new Electricity(); var engine = new Engine(fuel); var door = new Door(Electricity); var wheel = new Wheel(); var car = new Car(wheel, engine, door); car.move(); }
The problem function main() { var fuel = new Fuel(); var electricity = new Electricity(); var engine = new Engine(fuel); var door = new Door(Electricity); var wheel = new Wheel(); var car = new Car(wheel, engine, door); car.move(); }
The problem function main() { var fuel = new Fuel(); var electricity = new Electricity(); var engine = new Engine(fuel); var door = new Door(Electricity); var wheel = new Wheel(); var car = new Car(wheel, engine, door); car.move(); }
DI as framework function main() { var injector = new Injector(….); var car = injector.get(Car); car.move(); }
DI as framework function main() { var injector = new Injector(….); var car = injector.get(Car); car.move(); } Car.$inject = [‘wheel’, ‘engine’, ‘door’]; function Car(wheel, engine, door) { this.move = function() { … } }
DI as framework function main() { var injector = new Injector(….); var car = injector.get(Car); car.move(); } Car.$inject = [‘wheel’, ‘engine’, ‘door’]; function Car(wheel, engine, door) { this.move = function() { … } }
Angular testability is super-heroic! but…
“you still have to do the right thing.” - Angular Doc
Testability 1. Don’t use new 2. Don’t use globals
The Angular Way
Solid structured code
Testing components
Controller function RocketCtrl($scope) { $scope.maxFuel = 100; $scope.finalCheck = function() { if ($scope.currentFuel < $scope.maxFuel) { $scope.check = ‘ko’; } else { $scope.check = 'ok'; } }; }
Controller function RocketCtrl($scope) { $scope.maxFuel = 100; $scope.finalCheck = function() { if ($scope.currentFuel < $scope.maxFuel) { $scope.check = ‘ko’; } else { $scope.check = 'ok'; } }; }
var $scope = {}; var rc = $controller( 'RocketCtrl', { $scope: $scope } ); ! $scope.currentFuel = 80; $scope.finalCheck(); expect($scope.check).toEqual('ko'); Controller Test
Directive app.directive('rocketLaunchPad', function () { return { restrict: 'AE', replace: true, template: ‘<rocket-launch-pad> Rocket here <rocket-launch-pad>’ }; });
Directive Test it(‘Check launchpad was installed', function() { var element = $compile(“<rocket-launch-pad></ rocket-launch-pad>”)($rootScope); ! expect(element.html()).toContain("Rocket here"); });
Tools
Karma Protractor
Test Runner
Karma Run tests against real browsers
Karma Run tests against real browsers Unit tests
Config file > karma init
Config file > karma init - frameworks: [‘jasmine’]
Config file > karma init - frameworks: [‘jasmine’] - autoWatch: true
Config file > karma init - frameworks: [‘jasmine’] - files: [ ‘../tests/controllerSpec.js’ ], - autoWatch: true
Config file > karma init - frameworks: [‘jasmine’] - files: [ ‘../tests/controllerSpec.js’ ], - autoWatch: true - browsers: ['Chrome']
Using Karma > karma start config.js
Using Karma > karma start config.js
Protractor E2E Angular Testing Angular wrapper for WebDriver
Anatomy of a E2E test describe(‘…’, function() { it(‘…’, function() { browser.get(‘…’); element(by.model(‘…’)).sendKeys(..); ! var calculate = element(by.binding(‘…’)); ! expect(some.method()).toEqual(..); }); });
Global Variables describe(‘…’, function() { it(‘…’, function() { browser.get(‘…’); element(by.model(‘…’)).sendKeys(..); ! var calculate = element(by.binding(‘…’)); ! expect(some.method()).toEqual(..); }); });
Global Variables describe(‘…’, function() { it(‘…’, function() { browser.get(‘…’); element(by.model(‘…’)).sendKeys(..); ! var calculate = element(by.binding(‘…’)); ! expect(some.method()).toEqual(..); }); }); Super-Happy Panda!
Page Objects Protractor provides
Page Objects Protractor provides Debugging with superpowers
Page Objects Protractor provides Debugging with superpowers Angular-specific functions
Final Thoughts
Jacopo Nardiello Twitter: @jnardiello Questions?

Ultimate Introduction To AngularJS