ANGULARJS

The superheroic Javascript framework.

summary

  • What's a Framework?
  • Why AngularJS?
  • Crash course on JavaScript
  • Develop your own AngularJS app:
    • Variable interpolation
    • Two-way data binding (model/view)
    • Controllers
    • Routers
    • Filters
    • Directives
    • Building your own directives
  • What makes AngularJS different from other frameworks

Why A framework?


 

Complex web apps

Browser is no longer a dumb terminal

Why Angular


  • "What HTML would have been had it been designed for web apps"
  • HTML6!
  • Angular <3 JavaScript
  • MVC done right | A declarative user interface | Data models are POJO | Behavior with directives | Flexibility with filters | Write less code | DOM manipulations where they belong | Service providers where they belong | Context aware communication | Unit testing ready | 


<Angular />


Install (if you don't have 'em)


  • Node
  • git


then....


sudo npm install -g bower

First, JavaScript basics


  • Data types
  • Functions
  • Scope
  • JavaScript & DOM
  • Asynchronous Programming

Callback hell

var results = doThis(function(data) {
      doThat(data, function(data2) {
          mungeNumbers(data2, function(data3) {
              hideTracks(data3, function(data4) {
                  boostProfits(data4, function(data5) {
                      // On, and on, and on and on...
                  })
              })
          })
      })
  }) 

Promises


var promise = new Promise(function(resolve, reject) {
  resolve(1);
});

promise.then(function(val) {
  console.log(val); // 1
  return val + 2;
}).then(function(val) {
  console.log(val); // 3
}); 

Let's Start!

Checkout the project, then install dependencies and run the local server

git clone --depth=14 https://github.com/angular/angular-phonecat.git

cd angular-phonecat

npm install
git checkout -f step-0
npm start //Open: http://localhost:8000/app/index.html
http://docs.angularjs.org/tutorial

0 - The boostrap


app/index.html:

<!doctype html>
<html lang="en" ng-app>
<head>
  <meta charset="utf-8">
  <title>My HTML File</title>
  <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css">
  <link rel="stylesheet" href="css/app.css">
  <script src="bower_components/angular/angular.js"></script>
</head>
<body>

  <p>Nothing here {{'yet' + '!'}}</p>

</body>
</html>




git checkout -f step-0

Things to remember


  • Angular performs DOM compilation

    <p>1 + 2 = {{ 1 + 2 }}</p>

  • Creates scopes


My Working directory


1 - Browser readable html


AngularJS works with pure HTML directly. No need of ugly string-parsed template engines (Handlebars, Mustache, etc)

app/index.html:

  <ul>
    <li>
      <span>Nexus S</span>
      <p>
        Fast just got faster with Nexus S.
      </p>
    </li>
    <li>
      <span>Motorola XOOM™ with Wi-Fi</span>
      <p>
        The Next, Next Generation tablet.
      </p>
    </li>
  </ul>


git checkout -f step-1

2- Angular templates


In Angular, the view is a projection of the model through the HTML template

app/index.html:

<html ng-app="phonecatApp">
<head>
  ...
  <script src="bower_components/angular/angular.js"></script>
  <script src="js/controllers.js"></script>
</head>
<body ng-controller="PhoneListCtrl">

  <ul>
    <li ng-repeat="phone in phones">
      {{phone.name}}
      <p>{{phone.snippet}}</p>
    </li>
  </ul>

</body>
</html>

git checkout -f step-2
What's going on? 


Model and Controller

The data model (a simple array of phones in object literal notation) is now instantiated within the PhoneListCtrl controller. The controller is simply a constructor function that takes a $scope parameter:

app/js/controllers.js:


var phonecatApp = angular.module('phonecatApp', []);

phonecatApp.controller('PhoneListCtrl', function ($scope) {
  $scope.phones = [
    {'name': 'Nexus S',
     'snippet': 'Fast just got faster with Nexus S.'},
    {'name': 'Motorola XOOM™ with Wi-Fi',
     'snippet': 'The Next, Next Generation tablet.'},
    {'name': 'MOTOROLA XOOM™',
     'snippet': 'The Next, Next Generation tablet.'}
  ];
});

$Scope


 A scope can be seen as the glue which allows the template, model and controller to work together. 


Keeps the template, data model, and controller in sync.

3 - Filters

app/index.html:

  <div class="container-fluid">
    <div class="row">
      <div class="col-md-2">
        <!--Sidebar content-->

        Search: <input ng-model="query">

      </div>
      <div class="col-md-10">
        <!--Body content-->

        <ul class="phones">
          <li ng-repeat="phone in phones | filter:query">
            {{phone.name}}
            <p>{{phone.snippet}}</p>
          </li>
        </ul>

      </div>
    </div>
  </div>



git checkout -f step-3

Filtering Repeaters


<li ng-repeat="phone in phones | filter:query">

 The filter function uses the [[query]] value to create a new array that contains only those records that match the query.

4 - Two way data binding

app/index.html:

  Search: <input ng-model="query">
  Sort by:
  <select ng-model="orderProp">
    <option value="name">Alphabetical</option>
    <option value="age">Newest</option>
  </select>


  <ul class="phones">
    <li ng-repeat="phone in phones | filter:query | orderBy:orderProp">
      <span>{{phone.name}}</span>
      <p>{{phone.snippet}}</p>
    </li>
  </ul>





git checkout -f step-4

Angular creates a two way data-binding between the <select > element and the [[orderProp]] model. [[orderProp]] is then used as the input for the orderBy filter.




Did you notice?


No bloated DOM manipulation code is necessary!

5 - XHR & Dependency Injection


So, we have a small API serving...

[
 {
  "age": 13,
  "id": "motorola-defy-with-motoblur",
  "name": "Motorola DEFY\u2122 with MOTOBLUR\u2122",
  "snippet": "Are you ready for everything life throws your way?"
  ...
 },
...
]


what's a JSON anyways?

git checkout -f step-5

Consuming XHR


Remember jQuery's $.ajax calls?

We'll use Angular's $http service in our controller to make an HTTP request

app/js/controllers.js:

var phonecatApp = angular.module('phonecatApp', []);

phonecatApp.controller('PhoneListCtrl', function ($scope, $http) {
  $http.get('phones/phones.json').success(function(data) {
    $scope.phones = data;
  });

  $scope.orderProp = 'age';
});

Dependency injection





Bringing the dependencies (helpers/plugins/modules/whatever) you need in your controller




But why dependency injection?



  • Modularization (encapsulation)
  • Importing modules
  • File Minification

6. More about templates

app/phones/phones.json (sample snippet):

[
  {
    ...
    "id": "motorola-defy-with-motoblur",
    "imageUrl": "img/phones/motorola-defy-with-motoblur.0.jpg",
    "name": "Motorola DEFY\u2122 with MOTOBLUR\u2122",
    ...
  },
  ...
]

app/index.html:

...
        <ul class="phones">
          <li ng-repeat="phone in phones | filter:query | orderBy:orderProp" class="thumbnail">
            <a href="#/phones/{{phone.id}}" class="thumb"><img ng-src="{{phone.imageUrl}}"></a>
            <a href="#/phones/{{phone.id}}">{{phone.name}}</a>
            <p>{{phone.snippet}}</p>
          </li>
        </ul>
...

git checkout -f step-6

ngSrc


ng-src directive prevents the browser from treating the Angular {{ expression }} markup literally, and initiating a request to an invalid URL

url http://localhost:8000/app/{{phone.imageUrl}}

7. Router


hurray for one-page applications





git checkout -f step-7

Routing & Multiple Views


app/index.html:

<!doctype html>
<html lang="en" ng-app="phonecatApp">
<head>
...
  <script src="bower_components/angular/angular.js"></script>
  <script src="bower_components/angular-route/angular-route.js"></script>
  <script src="js/app.js"></script>
  <script src="js/controllers.js"></script>
</head>
<body>

  <div ng-view></div>

</body>
</html>
The $route service is usually used in conjunction with the ngView directive. The role of the ngView directive is to include the view template for the current route into the layout template.

The new app


app/js/app.js:

var phonecatApp = angular.module('phonecatApp', [
  'ngRoute',
  'phonecatControllers'
]);


phonecatApp.config(['$routeProvider',
  function($routeProvider) {
    $routeProvider.
      when('/phones', {
        templateUrl: 'partials/phone-list.html',
        controller: 'PhoneListCtrl'
      }).
      when('/phones/:phoneId', {
        templateUrl: 'partials/phone-detail.html',
        controller: 'PhoneDetailCtrl'
      }).
      otherwise({
        redirectTo: '/phones'
      });
  }]);

Multiple views...


app/partials/phone-list.html:

<div class="container-fluid">
  <div class="row">
    <div class="col-md-2">
      <!--Sidebar content-->

      Search: <input ng-model="query">
      Sort by:
      <select ng-model="orderProp">
        <option value="name">Alphabetical</option>
        <option value="age">Newest</option>
      </select>

    </div>
    <div class="col-md-10">
      <!--Body content-->

      <ul class="phones">
        <li ng-repeat="phone in phones | filter:query | orderBy:orderProp" class="thumbnail">
          <a href="#/phones/{{phone.id}}" class="thumb"><img ng-src="{{phone.imageUrl}}"></a>
          <a href="#/phones/{{phone.id}}">{{phone.name}}</a>
          <p>{{phone.snippet}}</p>
        </li>
      </ul>

    </div>
  </div>
</div>

Multiple controllers...

app/js/controllers.js:

var phonecatControllers = angular.module('phonecatControllers', []);

phonecatControllers.controller('PhoneListCtrl', ['$scope', '$http',
  function ($scope, $http) {
    $http.get('phones/phones.json').success(function(data) {
      $scope.phones = data;
    });

    $scope.orderProp = 'age';
  }]);

phonecatControllers.controller('PhoneDetailCtrl', ['$scope', '$routeParams',
  function($scope, $routeParams) {
    $scope.phoneId = $routeParams.phoneId;
  }]);


...and the router

...

phonecatApp.config(['$routeProvider',
  function($routeProvider) {
    $routeProvider.
      when('/phones', {
        templateUrl: 'partials/phone-list.html',
        controller: 'PhoneListCtrl'
      }).
      when('/phones/:phoneId', {
        templateUrl: 'partials/phone-detail.html',
        controller: 'PhoneDetailCtrl'
      }).
      otherwise({
        redirectTo: '/phones'
      });
  }]);

As we saw, the router wired URL patterns to certain controllers and views

 8 - More Templating



Implementing the phone details view, which is displayed when a user clicks on a phone in the phone list.







git checkout -f step-8


Expanding the PhoneDetailCtrl by using the $http service to fetch the json files.

app/js/controllers.js:

var phonecatControllers = angular.module('phonecatControllers',[]);

phonecatControllers.controller('PhoneDetailCtrl', ['$scope', '$routeParams', '$http',
  function($scope, $routeParams, $http) {
    $http.get('phones/' + $routeParams.phoneId + '.json').success(function(data) {
      $scope.phone = data;
    });
  }]);

Template

app/partials/phone-detail.html:

<img ng-src="{{phone.images[0]}}" class="phone">

<h1>{{phone.name}}</h1>

<p>{{phone.description}}</p>

<ul class="phone-thumbs">
  <li ng-repeat="img in phone.images">
    <img ng-src="{{img}}">
  </li>
</ul>

<ul class="specs">
  <li>
    <span>Availability and Networks</span>
    <dl>
      <dt>Availability</dt>
      <dd ng-repeat="availability in phone.availability">{{availability}}</dd>
    </dl>
  </li>
    ...
  <li>
    <span>Additional Features</span>
    <dd>{{phone.additionalFeatures}}</dd>
  </li>
</ul>

Title

9 - Filters


Formatting values:


12121212 -> $12,121,212.00
pepe PEcas Picapiedra -> Pepe Pecas Picapiedra





git checkout -f step-9

{{ expression | filter }}




app/partials/phone-detail.html:

...
    <dl>
      <dt>Infrared</dt>
      <dd>{{phone.connectivity.infrared | checkmark}}</dd>
      <dt>GPS</dt>
      <dd>{{phone.connectivity.gps | checkmark}}</dd>
    </dl>
...

Creating a filter...

app/js/filters.js:

angular.module('phonecatFilters', []).filter('checkmark', function() {
  return function(input) {
    return input ? '\u2713' : '\u2718';
  };
});


Injecting it...

app/js/app.js:

...
angular.module('phonecatApp', ['ngRoute','phonecatControllers','phonecatFilters']);
...

10 - Event Handlers


Adding a click event









git checkout -f step-10

jQuery


<img ng-src="{{img}}" class="img-clickable">

$( ".img-clickable" ).click(function() {
alert( "Handler for .click() called." );
});


AngularJS

<img ng-src="{{img}}" ng-click="setImage(img)">

11 - REST and Custom Services


Defines a custom service that represents a RESTful client. Using this client we can make requests to the server for data in an easier way:

  •  $http API
  • HTTP methods
  •  URLs



git checkout -f step-11

But first...

What's a factory?


http://jsfiddle.net/odiseo/nc8wnkqt/

Service



app/js/services.js.

var phonecatServices = angular.module('phonecatServices', ['ngResource']);

phonecatServices.factory('Phone', ['$resource',
  function($resource){
    return $resource('phones/:phoneId.json', {}, {
      query: {method:'GET', params:{phoneId:'phones'}, isArray:true}
    });
  }]);

Now we have


$scope.phones = Phone.query();

instead of

$http.get('phones/phones.json').success(function(data) {
  $scope.phones = data;
});

Directives



<date-picker></date-picker>

<input type="text" date-picker/>

<input type="text" class="date-picker"/>

<!--directive:date-picker-->

Fun time with directives




To-do miniapp:
http://jsfiddle.net/odiseo/WWCs8/


Currency live converter:
http://jsfiddle.net/odiseo/dj6mX/

Directive definition object


Full docs in https://docs.angularjs.org/guide/directive

var app = angular.module('myapp', []);
 
app.directive('helloWorld', function() {
  return {
      restrict: 'AE',
      replace: 'true',
      template: '<div>Hello World!!</div>'
  };
}); 

ExAmple

      <mayuscula model="query"></mayuscula>

directivas.directive('mayuscula', function() {
  return {
      restrict: 'E',
      scope: {'model': '='},
      link: function($scope, element, attr){

        $scope.$watch('model', function(newVal, oldVal){
            if (newVal !== oldVal) {
                $scope.model = newVal.toUpperCase();
            }
        });
      }
  };
}); 



What makes angular different?




The most important thing


Angular implements its own digest cycle



Made with Slides.com