AngularJS Intro

Data-binding, dependency injection, directives.

Created by Christian Köberl

Intro

AngularJS in 30 Seconds

AngularJS is more

  • MVC with fully two-way data-binding
  • Declarative form validation
  • Route management (enables deep linking)
  • Dependency Injection - yeah Spring for JS
  • Directives: reusable components, enhancing HTML, integrate 3rd party libs

MVC and Data-Binding

Model View Controller

  • Model
    a plain JavaScript object (POJSO)
  • View
    a HTML template using directives and expressions enclosed in {{ }}
  • Controller
    a JavaScript object that gets the $scope and services injected. Creates and changes the model.

Model View Controller in Code

Controllers and Interaction

Building an Application

Definining Modules

Sharing State Between Controllers

Using Other Services ($http)

Built-in Directives

Invoking/Using Directives

  • Attributes:
    • Standard: <span ng-bind="[expression]">
    • HTML5 data-attributes: <input data-ng-model="[expression]">
  • Tag: <ng-form>...</ng-form>
  • CSS class: <span class="ng-click: [expression]">
  • Comment: <!-- directive:my-directive -->
  • Hint: The JavaScript name of the directive is camelCase, e.g. ngModel

ng-bind And Expressions

  • This <span>{{ expression }}</span>
  • Is the same as <span ng-bind="expression"></span>
  • Expressions:
    • 27 + 15 ⇒ 42
    • person.name ⇒ get person object form $scope and use name attribute
    • myFunction() ⇒ get result of call to myFunction on $scope

ng-click And Other Events

  • Expressions in action directives should be functions:
    <button ng-click="doSomething()">Click Me</button>
  • Other events: ng-dblclick, ng-submit, ng-mouse* (mouseup, mousemove, ...)
  • ng-change is called on each change of the value
    <input type="checkbox" ng-model="confirmed" ng-change="change()" />

Loops And ng-repeat

Selects and ng-options

Filters

Using filters

Creating filters

The 'filter' Filter

Routes and Views

Routes? Views? What?

  • Navigable: back-button, bookmarks
  • Structure application in parts
  • Lazy load templates from server

Routes and Redirects

Routes and Controllers

Routes and Resolving

Creating Directives

Creating Reusable Components

Anatomy Of Directives

  • restrict - E - element, A - attribute, C - class, M - comment
  • scope - An isolate scope for the directive, if not there scope is inherited from enclosing controller
  • controller/require - A controller can be created per directive and injected into other directives via require
  • template/templateUrl - Template to use in rendering
  • replace - should the element be replaced?
  • transclude - use content of directive in the body of template?
  • compile/link - functions called on directives for manipulating DOM

Directives and Scope

Testing

Unit Testing services, filters, etc.

  • Test-Runner: Karma (aka Testacular)
  • angular-mocks.js to mock services
  • Jasmine for test specs

Testing a Weather Widget

Testing Controllers

  describe('Controller: WeatherCtrl', function() {

    it('calls weatherService to get weather', function() {
      inject(function($rootScope, $controller) {
        var weather = { temp : { current : 10 } }, 
            weatherService = { 
              getWeather : function() {
                return weather;
              }
            }, 
            scope = $rootScope.$new;

        $controller('WeatherCtrl', {
          $scope : scope,
          weatherService : weatherService
        });
        expect(scope.weather).toBe(weather);
      });
    });
  });

Testing Services

describe('Service: weatherService', function() {

    var url = 'http://api.openweathermap.org/data/2.5/weather?q=Salzburg,at&units=metric&callback=JSON_CALLBACK';
    var $httpBackend, weatherService;

    beforeEach(inject(function($injector) {
      $httpBackend = $injector.get('$httpBackend');
      weatherService = $injector.get('weatherService');
    }));

    it('maps the correct current temp', function() {
      $httpBackend.whenJSONP(url).respond({
        main : {
          temp : 10
        }
      });
      $httpBackend.expectJSONP(url);
      var weather = weatherService.getWeather();
      $httpBackend.flush();

      expect(weather.temp.current).toBe(10);
    });

  });

Testing Filters

  describe('Filter: temp', function() {
    var tempFilter;
    beforeEach(inject(function($filter) {
      tempFilter = $filter('temp');
    }));

    it('adds °C', function() {
      expect(tempFilter(3)).toBe('3.0°C');
    });

    it('handles precision correctly', function() {
      expect(tempFilter(3, 10)).toBe('3.0000000000°C');
    });

    it('handles non-numbers', function() {
      expect(tempFilter('a')).toBe('°C');
      expect(tempFilter({})).toBe('°C');
    });
  });

End-To-End Testing

Best Practices

Views ...

  • may read from the $scope: {{ data.name }}
  • may write on objects on the $scope
    ng-model="data.name"
  • may call methods on $scope: ng-click="save()"

  • should never write directly to $scope
    ng-model="name"
  • should not reference DOM

Controllers ...

  • should delegate work to services

  • should not reference DOM
  • should not reference other controllers

Services ...

  • should handle server calls ($http)
  • should not reference DOM, controllers and views

 

Directives ...

  • may reference the DOM
  • may reference services
  • should not directly handle server calls
  • should not reference controllers and views

Project Structure

  • Start project: Angular Seed, Yeoman
  • Structure by: 1. logical, 2. technical:
    scripts
    |- global
    | |- app.js
    | |- directives.js
    | |- filters.js
    | |- services.js
    |- module1
    | |- controllers.js 
    | |- services.js
    |- module2
    | |- controllers.js 
    | |- services.js

Tools

News

Animations

Controller As Syntax

THX

Questions?

Sources