WebApps with AngularJS

An overview of the framework

Henk Bakker

What is AngularJS

It's a structural framework for dynamic web apps
that's easy to maintain, in a fast and testable way.

The principles

  • Rapid development
  • Modularity
  • Built to be testable
  • Write less code

What it offers us

  • Controllers
  • Templates
  • Two-Way data bindings
  • Services
  • Directives
  • Dependency Injection

The simplest example


    <!DOCTYPE html>
    <html ng-app>
      <head>
        <script src="js/angular.min.js"></script>
      </head>
      <body>
        <form>
          <label>Your name?</label>
          <input type="text" ng-model="name" placeholder="Your name?">
        </form>
        <h3>My name is {{ name }}!</h3>
      </body>
    </html>
          

My name is {{ name }}!

$scope

$scope is an object that refers to the application model.
It connects the View and the Controller

myController.js


  function MyController($scope) {
    $scope.name = 'Henk Bakker';
  }
            

myView.html


  <form ng-controller="MyController">
    <input type="text" ng-model="name">
  </form>
            

Controllers

The controller is a function that augment the $scope object.
It's used to add a value or to add a behavior to the $scope.


    function TodoCtrl($scope) {
      $scope.todos = [
        { text: 'Learn AngularJS', done: true  },
        { text: 'Create an App',   done: false }
      ];

      $scope.addTodo = function () {
        $scope.todos.push({ text: $scope.todoText, done: false });
        $scope.todoText = '';
      };
    };
          

Templates

The templates are simply HTML5.
All the presentation logic of the app must be in there.


      <div ng-controller="TodoCtrl">
        <ul>
          <li ng-repeat="todo in todos">
            <input type="checkbox" ng-model="todo.done">
            <span>{{ todo.text }}</span>
          </li>
        </ul>
        <form ng-submit="addTodo()">
          <input type="text" ng-model="todoText">
          <button type="submit">Add</button>
        </form>
      </div>
            

Result

{{ todos | json }}

One-Way data binding

Most templating systems bind data in only one direction: they merge template and model components together into a view

Two-Way data binding

Two-way data binding is the automatic synchronization
of data between the model and view.

$scope inheritance

When a new $scope is created, it's added
as a child of it's parent $scope.

MyControllers.js


  function ParentController($scope) {
    $scope.person = {
      name     : 'Henk Bakker',
      helloText: ''
    };
  };

  function ChildController($scope) {
    $scope.sayHello = function () {
      $scope.person.helloText = "Hi " + $scope.person.name;
    }
  };
            

$scope inheritance 2

MyView.html


  <div ng-controller="ParentController">
    <form ng-controller="ChildController">
      <input type="text" ng-model="person.name" placeholder="Name">
      <button ng-click="sayHello()">Say hello</button>
    </form>
    <p>{{ person.helloText }}</p>
  </div>
          

person.helloText = {{ person.helloText }}

Services

Injctable objects that carry out specific tasks.
Provide a way to separate concerns and re-use code.

  • $http (ajax)
  • $locale
  • $timeout
  • $filter

$http

The $http service makes easier to integration with external APIs.

Main methods: .get, .post, .put, .delete, .jsonp


    $http.get('http://address-of.the/api')
      .success(successCallback)
      .error(errorCallback);

    $http.post('http://address-of.the/api', data)
      .success(successCallback)
      .error(errorCallback);
          

$http - example


    function BeerController($scope, $http) {
      $scope.makeRequest = function () {
        $http.jsonp('http://api.openbeerdatabase.com/v1/beers.json')
          .success(function (data, status) {
            $scope.beers = data.beers;
          })
          .error(function () {
            $scope.beers = [{ name: "No beer for you :(" }]
          });
      };
    };
          

    <div ng-controller="BeerController">
      <ul>
        <li ng-repeat="beer in beers | limitTo:15">
          {{ beer.name }} - {{ beer.brewery.name }}
        </li>
      </ul>
      <button ng-click="makeRequest()">Get beers</button>
    </div>
          

$http - Result

  • {{ beer.title }} {{ beer.brewery.title }}

Modules

Angular modules declaratively specify
how an application should be bootstrapped.


    var app = angular.module('myApp', ['third-part-module']);

    app.config(function () { ... });     
    app.controller('myController', ...); 
    app.service('myService', ...);       
          

    <html ng-app="myApp">
      ...
    </html>
          

Routing

In a more complex app you can use the $routeProvider service, to define which controller and template will be loaded in each path.


  var app = angular.module('myApp');

  app.config(function ($routeProvider) {
    $routeProvider
      .when('/', {
        controller :'mainController', templateUrl :'/views/index.html'
      })
      .when('/newPost/', {
        controller :'newPostController', templateUrl :'/views/newPost.html'
      })
      .when('/posts/:id', {
        controller :'postsController', templateUrl :'/views/posts.html'
      })
      .otherwise({ redirectTo : '/' });
    });
          

Directives

"Teach new tricks to the HTML"
  1. Create custom attributes
  2. Create custom HTML tags
    (based on W3C webcomponents specification)

Directives 2

All the attributes that begin with "ng" are AngularJS directives.

  • ng-app
  • ng-controller
  • ng-model
  • ng-repeat
  • ng-click
  • ng-view
  • ...

Directives 3

How to use directives


      <!doctype html>
      <html ng-app="myApp">
        <head>
          <script src="../js/angular.min.js"></script>
        </head>
        <body>
          <ul ng-controller="myListController">
            <li ng-repeat="item in items">
              {{ item.name }}
            </li>
          </ul>
        </body>
      </html>
          

Directives 4

You can also create you own directive.

  • element: <my-directive></my-directive>
  • atribute: <span my-directive="value"></span>
  • class: <span class="my-directive: value;"></span>
  • comment: <!-- directive: my-directive value -->

Directives 5


    var app = angular.module('myApp');

    app.directive('myDirective', function () {
      return {
        restrict: 'EA',
        link: function ($scope, element) {
          element.text('Text from directive');
        }
      };
    });
          

    <my-directive> </my-directive>  

    <div my-directive> </div>       
          

Directives 6


    var app = angular.module('myApp');

    app.directive('myDirective', function () {
      return {
        restrict: 'E',
        replace:  true,
        template: '

' link: function ($scope, element) { element.text('Text from directive'); } }; });

    <my-directive> </my-directive>             

    <h1 class="title">Text from directive</h1> 
          

Testing your App

A framework to be easily tested

Tools:

  • Karma Test runner
  • Jasmine Test framework

Testing a controller


  describe('Testing Controller', function () {
    var ctrl, scope;

    beforeEach(angular.mock.module('myApp'));

    beforeEach(inject(function ($controller, $rootScope) {
      scope = $rootScope.$new();
      ctrl  = $controller('myController', { $scope: scope });
    }));

    it('should exist a controller called myController', function() {
      expect(scope).not.toBeUndefined();
    });
  });
          

End-to-end Tests


  describe('Grocery list', function () {
    beforeEach(function () {
      browser().navigateTo('/');
    });

    it('filters the grocery list based on the search query', function() {
      expect(repeater('.groceries li').count()).toBe(5);

      input('query').enter('b');
      expect(repeater('.groceries li').count()).toBe(3);

      input('query').enter('blueberry');
      expect(repeater('.groceries li').count()).toBe(1);
    });
  });
          

DEMO TIME

JukeTube

Demo | Source

jHipster

Homepage

Ionic

Homepage

Learn

References

The End

Henk Bakker