Author Archives: admin

AngularJS: Notes On AngularJS Scope Life-Cycle

[Fuente: http://onehungrymind.com/notes-on-angularjs-scope-life-cycle/]

I have had the incredible good fortune of being part of some very talented developers ramping up on AngularJS. It is inevitable that questions surrounding scope life-cycle work their way into the process. These usually come in the form of “But how does AngularJS know when this value has changed so that it can update bindings?” or “Hey I am listening for this DOM event in my directive and when I update scope, nothing is happening… what is the deal?” or even “Oh my goodness! How does it do that!? IS IT MAGIC!?”

At the core of AngularJS is the scope life-cycle and so I wanted to take this opportunity to elaborate on some of the fundamental aspects of how scope works in AngularJS. I have tried to distill this concept down to the most important bits so that a new developer could grasp scope life-cycle in less than 10 minutes and experienced developers could explain it in less than 10 minutes.

First Things First

Misko Hevery wrote a brilliant explanation of dirty checking vs change listeners on Stack Overflow that I think should be required reading for anyone coming into AngularJS. I hereby vote that it be included in the AngularJS docs IMMEDIATELY!

http://stackoverflow.com/questions/9682092/databinding-in-angularjs/9693933#9693933

I want to point out a few things as it relates to what I want to talk about here:

  1. AngularJS compares a value with its previous value and if it has changed then a change event is fired. This is dirty checking in a nutshell.
  2. In AngularJS, a digest is the cycle that performs dirty checking. This is initiated via $digest().
  3. If something happens outside of AngularJS, you need to let AngularJS know to execute a digest cycle and you do that via $apply which calls $digest.

Now on to the nuts and bolts! I think that the scope life-cycle IS dirty checking and all the broad strokes can be summarized in $digest, watchExpressions and $apply.

$digest

This is the “heartbeat” of an AngularJS application. $digest processes all the watchExpressions for the current scope and its children.

So what happens when a watchExpression is processed? I will get into that a bit more when I talk about watchExpressions, but basically the value of the current watchExpression is compared with the value of the previous watchExpression, and if they do not match then it is “dirty” and a listener is fired.

With that said, you should not call $digest directly but call $apply which will force a $digest cycle. I will get more into the reasoning behind this in just a moment.

watchExpressions

Behind every $digest cycle is a good watchExpression. watchExpressions return the value of what is being watched on every $digest cycle. This is the trenches of dirty checking. If the value of the current watchExpression call and the previous watchExpression call do not match then a listener is fired.

Most watchExpressions are created implicitly within AngularJS, but you can also create them manually. Let me show you how to do that:

1
scope.$watch(‘name’, function(newValue, oldValue) { /* Do something clever here */ });

Most of the time a watchExpression is just the name of a property you want to watch. In this example the watchExpression is “name”. If “name” changes then the listener function is called.

angular.equals is used to determine the equality of the two expressions while angular.copy is used to store the value of current value of a watchExpression for later comparison.

It is also important to understand that when one listener fires, it may change the model which will fire other listeners and so the watchers keep re-running until no more watchers are firing.

$apply

I like to think of $apply as a courier service that the outside world can recruit to tell AngularJS that something has happened and drop off an optional expression to be handled.

I mentioned previously that you use $apply to force a $digest cycle, but that is just one part of what happens with $apply. To follow the courier analogy, $apply hand delivers the message and possibly a package to the sweet lady at the front desk named $evalerie, but you can call her $eval. GROAN! Okay! Back on track! $eval checks to make sure that $apply dropped off a legitimate expression. If something is wrong while it is being evaluated then an exception is thrown and passed to the $exceptionHandler service. From there, $digest is called to kick off the $digest cycle.

Application level error handling is a nice feature that I highly recommend you utilize, especially as your application grows in complexity. The fact that we get it for free with $apply is really cool and why you should use it over $digest.

So when do you use $apply?

Good question! One of the main reasons you use $apply is when browser DOM events have triggered outside of AngularJS. jQuery I’m looking at you!

You may also need to use it for setTimeout events, XHR callbacks, and integrating with 3rd party libraries.

Here is a fiddle I put together to illustrate a use of $apply
http://jsfiddle.net/simpulton/huKHQ/

I freely admit that this example is a bit contrived – it stems from a real question my buddy Fritz had a few days ago.

The part I want to draw your attention to is in the code below:

1
2
3
4
5
6
7
8
9
$(‘.testButtonWithApply’).on(‘click’, function(){
$scope.$apply(function() {
$scope.handleClick(‘Scope apply’);
});
});

$(‘.testButtonWithoutApply’).on(‘click’, function(){
$scope.handleClick(‘This will not work’);
});

Both functions are listening for events via jQuery and then making a request back into AngularJS from the event handler. The difference between the two is that I have wrapped the handleClick function in a function expression that I pass to $apply. I could have just called handleClick and THEN $apply but it is better to use the function expression so you get error handling.

More than once calling $apply has been the difference between me getting the behavior I expected, and crickets as nothing happened at all.

Conclusion

This concludes my primer on AngularJS scope life-cycle and what is behind the “magic” that blew me away when I started digging into AngularJS.

So to summarize, there is an internal cycle called $digest that runs through the application and executes watch expressions and compares the value returned with the previous value and if the values do not match then a listener is fired. This $digest cycle keeps looping until no more listeners are fired. You can call $digest directly, but it is recommended that you call $apply because it wraps a $digest call with an error handling mechanism. You call $apply when something outside of AngularJS happens that you need to notify AngularJS about. Well, I guess when you say it like that… it doesn’t seem so hard. Cheers!

Resources

The Misko Hevery Breakdown
http://stackoverflow.com/questions/9682092/databinding-in-angularjs/9693933#9693933

$apply Example
http://jsfiddle.net/simpulton/huKHQ/

And be sure to check out the documentation. I have read it like ten times and am still learning things.
http://docs.angularjs.org/api/ng.$rootScope.Scope

AngularJS: Building Huuuuuge Apps with AngularJS

[Fuente: http://briantford.com/blog/huuuuuge-angular-apps.html]

The AngularJS documentation is great for getting started and for looking up specific API calls. However, it doesn’t really tell you how to organize and manage your app as it grows to tens or hundreds of thousands of lines of code. I’ve collected here some of my observations and best practices for how to manage your sprawling application. First we’ll take a look at organization, then move on to some tips on improving performance, and conclude with a brief summary on tools, servers, and build processes. While this post will focus on big apps in particular, there’s a great video on YouTube from the December 2012 AngularJS meetup on best practices that’s also worth checking out.

Don’t Write a Huge App

The best advice about huge apps is not to make them. Write small, focused, modular parts, and progressively combine them into bigger things to make your app. (This advice brought to you by node.js hacker and all around cool dude @substack)

Organization

Probably the biggest question with large apps is where to put all of that code. On your toolbelt of organizational tools, you’ve got files, directories, modules, services, and controllers. For a quick overview of good AngularJS project structure, check out the Angular Seed on Github. However I’d like to go a bit more in-depth and offer some additional advice on project structure. Let’s start with directories and work our way down the list.

Directories

This is the typical folder layout that I recommend:

root-app-folder
├── index.html
├── scripts
│   ├── controllers
│   │   └── main.js
│   │   └── ...
│   ├── directives
│   │   └── myDirective.js
│   │   └── ...
│   ├── filters
│   │   └── myFilter.js
│   │   └── ...
│   ├── services
│   │   └── myService.js
│   │   └── ...
│   ├── vendor
│   │   ├── angular.js
│   │   ├── angular.min.js
│   │   ├── es5-shim.min.js
│   │   └── json3.min.js
│   └── app.js
├── styles
│   └── ...
└── views
    ├── main.html
    └── ...

As you add more files, it might make sense to create subdirectories to further organize controllers and services. For instance, I often find myself making a models directory inside of services. My rule of thumb is to only further sort files into directories if there is some rational hierarchy by which you can organize the files.

Files

Each file should have one “thing” in it, where a “thing” is a controller, directive, filter, or service. This makes for small, focused files. It also helps create a litmus test for how APIs are doing. If you find yourself flipping back and forth through files too frequently, this is an indication that your APIs are too complex. You should rethink, refactor, and simplify.

I would make an exception for closely related directives. For example, if you have an <pane> directive that requires <panel> to be a parent, those should be in the same file.

Modules

Define and configure all modules in app.js:

angular.module('yourAppName', ['yourAppDep']);
angular.module('yourAppDep');

Define controllers, services, etc. on modules like this:

angular.module('yourAppDep').controller('MyCtrl', function () {
  // ...
});

Although we (the AngularJS team) have discussed being able to lazy-load at the module granularity, it’s not yet on the roadmap for the next version of Angular. There was a good discussion on Google+ about using multiple top-level AngularJS apps to produce a lazy-loading-like effect. I haven’t tried it or seen it done, but if you desperately need to reduce payload size, that’s certainly one way to do it.

The only remaining question is how to subdivide controllers, directives, services, and filters into modules. The Angular Seed puts filters, services, and directives into separate modules, but that seems a bit silly to me. Depending on the app, I’d be more inclined to organize modules by page/route. From a performance perspective, it doesn’t really matter how you organize your modules, so choose whatever method best suits your project.

Dependencies

In general, services, controllers, directives, etc. should have as few dependencies as possible. This is good software development practice in general, but it’s worth mentioning. This also will help in testing.

APIs should be layered. Controllers especially should not be synthesizing different levels of abstraction.

Directives

Use an app-specific prefix for directives. This is useful for avoiding collisions with 3rd party components. On the subject of 3rd party components, there’s a growing community site called ngmodules that looks promising.

For example, if your app is called “The Best Todo List App Ever,” you might prefix your directives with “btla.”

angular.module('yourAppDep').directive('btlaControlPanel', function () {
  // ...
});

You might worry about directive names becoming too long, but I haven’t seen it become problematic. You’ll never really see a performance hit from long directive names, thanks to gzip compression.

Services

angular.module('yourAppDep').service('MyCtrl', function () {
  // ...
});

Models

AngularJS is unique among JavaScript frameworks in that it gives you complete control over your model layer. I think this is one of the great strengths of Angular, because at the core of your application is your data, and data varies wildly from app to app. My biggest recommendation is to consider what data you will be using, and how you will store it.

If you’re using a NoSQL datastore like CouchDB or MongoDB, you might be content working with plain-old JavaScript Objects (POJO) and functional helpers. If you’re using a relational database like MySQL, you might want psuedo-classes with methods for mutating, serializing, and deserializing the data. If your server provides a RESTful interface, $resource might be a good place to start. These are just suggestions; any of these approaches might be useful outside of the situations I described. With so many options, this is sometimes a challenging decision to make. But thinking hard about your data will pay off.

In general, you’ll find many great utilities for dealing with models in Underscore.js, the utility library that also powers Backbone.js.

Controllers

By convention, controller names should start with a capital letter and end with “Ctrl”.

angular.module('yourAppDep').controller('MyCtrl', function () {
  // ...
});

Remember that controllers can be reused. This seems obvious, but I’ve caught myself reimplementing features in different controllers. For example, consider a user control panel that allows a user to change application settings and a dialog box prompting a user to change a setting. Both could share a common controller.

Performance

AngularJS apps are generally very, very fast. Most apps really don’t need any sort of special optimization, so unless you’re experiencing poor performance, your time is better spent improving your app in other ways. For these exceptional cases Angular provides some excellent ways to address performance issues. First though, it’s important to identify the cause of performance degradation. For that, I highly recommend the AngularJS Batarang Chrome extension or Chrome’s built-in CPU profiling.

Optimizing the Digest Cycle

AngularJS uses dirty checking in its “digest cycle.” For the uninitiated, you can read more about the digest cycle in the official docs and in this StackOverflow answer.

Sometimes, you want to be able to avoid a digest cycle. One common situation in real-time WebSocket’ed apps is that you don’t always want to digest when you receive a message. Consider a real-time game where messages are sent from the server 30 or more times per second.

app.factory('socket', function ($rootScope) {
  var socket = io.connect();
  return {
    on: function (eventName, callback) {
      socket.on(eventName, function () {  // this could fire many times a second
        var args = arguments;
        $rootScope.$apply(function () {
          callback.apply(socket, args);
        });
      });
    }
    // ...
  };
});

One great way to deal with this is to “throttle” the requests so a digest only happens a few times a second. Underscore.js provides such a function, but the implementation is pretty tiny, so I’ve reproduced it inside the socket service below:

app.factory('socket', function ($rootScope) {

  // Underscore.js 1.4.3
  // http://underscorejs.org
  // (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
  // Underscore may be freely distributed under the MIT license.

  // _.throttle
  // https://github.com/documentcloud/underscore/blob/master/underscore.js#L626
  // Returns a function, that, when invoked, will only be triggered at most once
  // during a given window of time.
  var throttle = function (func, wait) {
    var context, args, timeout, result;
    var previous = 0;
    var later = function() {
      previous = new Date();
      timeout = null;
      result = func.apply(context, args);
    };
    return function() {
      var now = new Date();
      var remaining = wait - (now - previous);
      context = this;
      args = arguments;
      if (remaining <= 0) {
        clearTimeout(timeout);
        timeout = null;
        previous = now;
        result = func.apply(context, args);
      } else if (!timeout) {
        timeout = setTimeout(later, remaining);
      }
      return result;
    };
  };

  var socket = io.connect();
  return {
    on: function (eventName, callback) {
      socket.on(eventName, throttle(function () {  // limit to once every 500ms
        var args = arguments;
        $rootScope.$apply(function () {
          callback.apply(socket, args);
        });
      }, 500));
    }
    // ...
  };
});

Other times, you know an incoming change will only affect certain scopes, and might want to just dirty check those. For those cases, you can call $scope.$digest instead of $scope.$apply$digest will only run the digest cycle on the scope it’s called on, and all of that scope’s children.

Finally, to keep digest cycles short, watch expressions in $scope.$watch should be as fast as possible. Wherever possible, avoid deep comparisons. Remember, you only need to compare things that affect the view.

Filters

Filters are called at least twice during every digest cycle. For that reason, it’s best if they are lightweight.

In cases where data is loaded and displayed, but not modified, moving the transformations done in filters to run on the data when it’s fetched might be better. This is actually relatively simple, since AngularJS exposes filters to be used programmatically through $filter.

For instance, you load a list of names in lower-case, but need title-case, so you have a filter that does the transformation:

{{someModel.name | titlecase}}

It’s pretty easy to move this to your controller and change the name to title-case when it’s loaded.

angular.module('myApp').controller('MyCtrl', function ($scope, $http, $filter) {
  $http.get('/someModel')
    .success(function (data) {
      $scope.someModel = data;
      // run the same "titlecase" filter inside the controller after loading the data
      $scope.someModel.name = $filter('titlecase')($scope.someModel.name);
    });
});

For cases that you can’t transform data upon retrieval, memoization is a great way to speed up your expensive filters without much work. Addy Osmani has a pretty great article on memoization in JavaScript that’s worth a read. As for implementation, Underscore.js provides an excellent memoization function that you can use. This technique should not be used blindly, however. Memoization only helps when you’re calling a filter frequently with the same, unchanged models. For rapidly changing models that have many different values throughout your application’s runtime, you’re better off not memoizing filters that act on that data.

Testing

Testing is immensely important for large projects. Tests allow you to refactor with confidence, which is essential in keeping code clean on a large project. Large apps should have both unit and end-to-end (E2E) tests. Unit tests are great in helping you pinpoint problems, and E2E tests ensure that the whole app works as expected. Each controller, service, filter, and directive should have a set of unit tests. Each feature of your app should have an E2E test.

This is another topic that deserves more attention. Fortunately, the AngularJS documentation has more to say on both unit and E2E tests. My colleage Vojta Jina also spoke recently about testing directives. The video is on YouTube, and definitely worth a watch.

Tools

I’ve been doing a lot of work on Yeoman to try to consolidate best practices and good project structure, and make what little boilerplate AngularJS has automagically generated. I highly recommend checking it out.

The AngularJS Batarang is another of my projects, and is great for both debugging and finding performance bottlenecks.

Server

As you’re aware, you can use any server you want with AngularJS. It is strictly a client-side library. My recommendation and prefered setup is to use Node.js alongside nginx. I use nginx to server static files, and Node to create a RESTful API and/or socketed app. Node.js hits a sweet spot between ease of use and speed. For instance, it’s relatively easy to spawn worker processes or create a webserver that can use all of your fancy server’s cores.

As for cloud providers, I’ve used both Nodejitsu and Linode to great success. Nodejitsu is great if you’re sticking strictly to node. It makes deploying your app easy, and you don’t have to worry about your server environment. You can spawn additional node processes as needed to scale and handle bigger loads. If you need more control over your server environment, Linode gives you root to a fleet of VMs. Linode also provides a nice API for managing VMs. And there are plenty of other great cloud server providers that I haven’t had a chance to look at yet myself.

Configuring and scaling a backend is a subject worthy of its own article, and there’s no shortage of great advice elsewhere for that.

Build Process

Admittedly, this is one thing Angular needs to be better at, and one of my huge aims for 2013 is to help on this front. I’ve released ngmin, a tool that I hope will ultimately solve the problem of minimizing AngularJS apps for production.

For now, I think your best bet is concatenating your JavaScript files with app.js first, then using ngmin to annotate DI functions, and finally minifying with Closure Compiler with the flag--compilation_level SIMPLE_OPTIMIZATIONS. You can see an example of this at work in the build process for angular.js.

I don’t recommend using RequireJS with AngularJS. Although it’s certainly possible, I haven’t seen any instance where RequireJS was beneficial in practice.

Conclusion

AngularJS is one of the most suitable JS frameworks for writing large apps. Out-of-the-box, it’s very fast and greatly helps structure your app. But hopefully this advice is useful as you push the boundaries for what’s possible with AngularJS.

Have some advice for scaling Angular apps? Tweetemail, or send a pull request on Github.

AngularJS: Creating Custom Directives

[Fuente: http://docs.angularjs.org/guide/directive ]

Note: this guide is targeted towards developers who are already familiar with AngularJS basics. If you’re just getting started, we recommend the tutorial first. If you’re looking for the directives API, we recently moved it to$compile.

This document explains when you’d want to create your own directives in your AngularJS app, and how to implement them.

What are Directives?

At a high level, directives are markers on a DOM element (such as an attribute, element name, or CSS class) that tell AngularJS’s HTML compiler ($compile) to attach a specified behavior to that DOM element or even transform the DOM element and its children.

Angular comes with a set of these directives built-in, like ngBindngModel, and ngView. Much like you create controllers and services, you can create your own directives for Angular to use. When Angular bootstraps your application, the HTML compiler traverses the DOM matching directives against the DOM elements.

What does it mean to “compile” an HTML template? For AngularJS, “compilation” means attaching event listeners to the HTML to make it interactive. The reason we use the term “compile” is that the recursive process of attaching directives mirrors the process of compiling source code in compiled programming languages.

Matching Directives

Before we can write a directive, we need to know how Angular’s HTML compiler determines when to use a given directive.

In the following example, we say that the <input> element matches the ngModel directive.

<input ng-model="foo">

The following also matches ngModel:

<input data-ng:model="foo">

Angular normalizes an element’s tag and attribute name to determine which elements match which directives. We typically refer to directives by their case-sensitive camelCase normalized name (e.g. ngModel). However, since HTML is case-insensitive, we refer to directives in the DOM by lower-case forms, typically using dash-delimited attributes on DOM elements (e.g. ng-model).

The normalization process is as follows:

  1. Strip x- and data- from the front of the element/attributes.
  2. Convert the :-, or _-delimited name to camelCase.

Here are some equivalent examples of elements that match ngBind:

index.html

<!doctype html>
<html ng-app="docsBindExample">
  <head>
    <script src="http://code.angularjs.org/1.2.9/angular.min.js"></script>
    <script src="script.js"></script>
  </head>
  <body>
    <div ng-controller="Ctrl1">
      Hello <input ng-model='name'> <hr/>
      <span ng-bind="name"></span> <br/>
      <span ng:bind="name"></span> <br/>
      <span ng_bind="name"></span> <br/>
      <span data-ng-bind="name"></span> <br/>
      <span x-ng-bind="name"></span> <br/>
    </div>
  </body>
</html>
scripts.js
angular.module('docsBindExample', [])
  .controller('Ctrl1', function Ctrl1($scope) {
    $scope.name = 'Max Karl Ernst Ludwig Planck (April 23, 1858 – October 4, 1947)';
  });
Best Practice: Prefer using the dash-delimited format (e.g. ng-bind for ngBind). If you want to use an HTML validating tool, you can instead use the data-prefixed version (e.g. data-ng-bind for ngBind). The other forms shown above are accepted for legacy reasons but we advise you to avoid them.

$compile can match directives based on element names, attributes, class names, as well as comments.

All of the Angular-provided directives match attribute name, tag name, comments, or class name. The following demonstrates the various ways a directive (myDir in this case) can be referenced from within a template:

<my-dir></my-dir>
<span my-dir="exp"></span>
<!-- directive: my-dir exp -->
<span></span>

Best Practice: Prefer using directives via tag name and attributes over comment and class names. Doing so generally makes it easier to determine what directives a given element matches.

Best Practice: Comment directives were commonly used in places where the DOM API limits the ability to create directives that spanned multiple elements (e.g. inside <table> elements). AngularJS 1.2 introduces ng-repeat-start and ng-repeat-end as a better solution to this problem. Developers are encouraged to use this over custom comment directives when possible.

Text and attribute bindings

During the compilation process the compiler matches text and attributes using the $interpolate service to see if they contain embedded expressions. These expressions are registered as watches and will update as part of normal digest cycle. An example of interpolation is shown below:

<a ng-href="img/{{username}}.jpg">Hello {{username}}!</a>

ngAttr attribute bindings

Web browsers are sometimes picky about what values they consider valid for attributes.

For example, considering this template:

<svg>
  <circle cx="{{cx}}"></circle>
</svg>

We would expect Angular to be able to bind to this, but when we check the console we see something likeError: Invalid value for attribute cx="{{cx}}". Because of the SVG DOM API’s restrictions, you cannot simply write cx="{{cx}}".

With ng-attr-cx you can work around this problem.

If an attribute with a binding is prefixed with the ngAttr prefix (denormalized as ng-attr-) then during the binding will be applied to the corresponding unprefixed attribute. This allows you to bind to attributes that would otherwise be eagerly processed by browsers (e.g. an SVG element’s circle[cx] attributes).

For example, we could fix the example above by instead writing:

<svg>
  <circle ng-attr-cx="{{cx}}"></circle>
</svg>

Creating Directives

First let’s talk about the API for registering directives. Much like controllers, directives are registered on modules. To register a directive, you use the module.directive API. module.directive takes the normalized directive name followed by a factory function. This factory function should return an object with the different options to tell $compile how the directive should behave when matched.

The factory function is invoked only once when the compiler matches the directive for the first time. You can perform any initialization work here. The function is invoked using $injector.invoke which makes it injectable just like a controller.

Best Practice: Prefer using the definition object over returning a function.We’ll go over a few common examples of directives, then dive deep into the different options and compilation process.

Best Practice: In order to avoid collisions with some future standard, it’s best to prefix your own directive names. For instance, if you created a <carousel> directive, it would be problematic if HTML7 introduced the same element. A two or three letter prefix (e.g. btfCarousel) works well. Similarly, do not prefix your own directives with ng or they might conflict with directives included in a future version of Angular.

For the following examples, we’ll use the prefix my (e.g. myCustomer).

Template-expanding directive

Let’s say you have a chunk of your template that represents a customer’s information. This template is repeated many times in your code. When you change it in one place, you have to change it in several others. This is a good opportunity to use a directive to simplify your template.

Let’s create a directive that simply replaces its contents with a static template:

Source

index.html

<!doctype html>
<html ng-app="docsSimpleDirective">
  <head>
    <script src="http://code.angularjs.org/1.2.9/angular.min.js"></script>
    <script src="script.js"></script>
  </head>
  <body>
    <div ng-controller="Ctrl">
      <div my-customer></div>
    </div>
  </body>
</html>
scripts.js
angular.module('docsSimpleDirective', [])
  .controller('Ctrl', function($scope) {
    $scope.customer = {
      name: 'Naomi',
      address: '1600 Amphitheatre'
    };
  })
  .directive('myCustomer', function() {
    return {
      template: 'Name: {{customer.name}} Address: {{customer.address}}'
    };
  });

Notice that we have bindings in this directive. After $compile compiles and links <div my-customer> </div>, it will try to match directives on the element’s children. This means you can compose directives of other directives. We’ll see how to do that in an example below.

In the example above we in-lined the value of the template option, but this will become annoying as the size of your template grows.

Best Practice: Unless your template is very small, it’s typically better to break it apart into its own HTML file and load it with the templateUrl option.If you are familiar with ngIncludetemplateUrl works just like it. Here’s the same example using templateUrl instead:

<!doctype html>
<html ng-app="docsTemplateUrlDirective">
  <head>
    <script src="http://code.angularjs.org/1.2.9/angular.min.js"></script>
    <script src="script.js"></script>
  </head>
  <body>
    <div ng-controller="Ctrl">
      <div my-customer></div>
    </div>
  </body>
</html>
Name: {{customer.name}} Address: {{customer.address}}
angular.module('docsTemplateUrlDirective', [])
  .controller('Ctrl', function($scope) {
    $scope.customer = {
      name: 'Naomi',
      address: '1600 Amphitheatre'
    };
  })
  .directive('myCustomer', function() {
    return {
      templateUrl: 'my-customer.html'
    };
  });

Great! But what if we wanted to have our directive match the tag name <my-customer> instead? If we simply put a <my-customer> element into the HTML, it doesn’t work.

Note: When you create a directive, it is restricted to attribute only by default. In order to create directives that are triggered by element name, you need to use the restrict option.

The restrict option is typically set to:

  • 'A' – only matches attribute name
  • 'E' – only matches element name
  • 'AE' – matches either attribute or element name

Let’s change our directive to use restrict: 'E':

Source

<!doctype html>
<html ng-app="docsRestrictDirective">
  <head>
    <script src="http://code.angularjs.org/1.2.9/angular.min.js"></script>
    <script src="script.js"></script>
  </head>
  <body>
    <div ng-controller="Ctrl">
      <my-customer></my-customer>
    </div>
  </body>
</html>
angular.module('docsRestrictDirective', [])
  .controller('Ctrl', function($scope) {
    $scope.customer = {
      name: 'Naomi',
      address: '1600 Amphitheatre'
    };
  })
  .directive('myCustomer', function() {
    return {
      restrict: 'E',
      templateUrl: 'my-customer.html'
    };
  });

For more on the restrict property, see the API docs.

When should I use an attribute versus an element? Use an element when you are creating a component that is in control of the template. The common case for this is when you are creating a Domain-Specific Language for parts of your template. Use an attribute when you are decorating an existing element with new functionality.

Using an element for the myCustomer directive is clearly the right choice because you’re not decorating an element with some “customer” behavior; you’re defining the core behavior of the element as a customer component.

Isolating the Scope of a Directive

Our myCustomer directive above is great, but it has a fatal flaw. We can only use it once within a given scope.In its current implementation, we’d need to create a different controller each time In order to re-use such a directive:

Source

<!doctype html>
<html ng-app="docsScopeProblemExample">
  <head>
    <script src="http://code.angularjs.org/1.2.9/angular.min.js"></script>
    <script src="script.js"></script>
  </head>
  <body>
    <div ng-controller="NaomiCtrl">
      <my-customer></my-customer>
    </div>
    <hr>
    <div ng-controller="IgorCtrl">
      <my-customer></my-customer>
    </div>
  </body>
</html>

Name: Naomi Address: 1600 Amphitheatre

Name: Igor Address: 123 Somewhere

This is clearly not a great solution.

What we want to be able to do is separate the scope inside a directive from the scope outside, and then map the outer scope to a directive’s inner scope. We can do this by creating what we call an isolate scope. To do this, we can use a directive’s scope option:

Source

<!doctype html>
<html ng-app="docsIsolateScopeDirective">
<head>
<script src="http://code.angularjs.org/1.2.9/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body>
	<div ng-controller="Ctrl">
		<my-customer info="naomi"></my-customer>
		<hr>
		<my-customer info="igor"></my-customer>
	</div>
</body>
</html>
Name: {{customerInfo.name}} Address: {{customerInfo.address}}
angular.module('docsIsolateScopeDirective', []).controller('Ctrl',
		function($scope) {
			$scope.naomi = {
				name : 'Naomi',
				address : '1600 Amphitheatre'
			};
			$scope.igor = {
				name : 'Igor',
				address : '123 Somewhere'
			};
		}).directive('myCustomer', function() {
	return {
		restrict : 'E',
		scope : {
			customerInfo : '=info'
		},
		templateUrl : 'my-customer-iso.html'
	};
});

Demo

Name: Naomi Address: 1600 Amphitheatre


Name: Igor Address: 123 Somewhere

Looking at index.html, the first <my-customer> element binds the info attribute to naomi, which we have exposed on our controller’s scope. The second binds info to igor.

Let’s take a closer look at the scope option:

//...
scope: {
  customerInfo: '=info'
},
//...

The scope option is an object that contains a property for each isolate scope binding. In this case it has just one property:

  • Its name (customerInfo) corresponds to the directive’s isolate scope property customerInfo.
  • Its value (=info) tells $compile to bind to the info attribute.
Note: These =attr attributes in the scope option of directives are normalized just like directive names. To bind to the attribute in <div bind-to-this="thing">, you’d specify a binding of =bindToThis.

For cases where the attribute name is the same as the value you want to bind to inside the directive’s scope, you can use this shorthand syntax:

...
scope: {
  // same as '=customer'
  customer: '='
},
...

Besides making it possible to bind different data to the scope inside a directive, using an isolated scope has another effect.

We can show this by adding another property, vojta, to our scope and trying to access it from within our directive’s template:

Source

<!doctype html>
<html ng-app="docsIsolationExample">
  <head>
    <script src="http://code.angularjs.org/1.2.9/angular.min.js"></script>
    <script src="script.js"></script>
  </head>
  <body>
    <div ng-controller="Ctrl">
      <my-customer info="naomi"></my-customer>
    </div>
  </body>
</html>
Name: {{customerInfo.name}} Address: {{customerInfo.address}}
<hr>
Name: {{vojta.name}} Address: {{vojta.address}}
angular.module('docsIsolationExample', [])
  .controller('Ctrl', function($scope) {
    $scope.naomi = { name: 'Naomi', address: '1600 Amphitheatre' };

    $scope.vojta = { name: 'Vojta', address: '3456 Somewhere Else' };
  })
  .directive('myCustomer', function() {
    return {
      restrict: 'E',
      scope: {
        customerInfo: '=info'
      },
      templateUrl: 'my-customer-plus-vojta.html'
    };
  });

Demo

Name: Naomi Address: 1600 Amphitheatre


Name: Address:

Notice that {{vojta.name}} and {{vojta.address}} are empty, meaning they are undefined. Although we defined vojta in the controller, it’s not available within the directive.

As the name suggests, the isolate scope of the directive isolates everything except models that you’ve explicitly added to the scope: {} hash object. This is helpful when building reusable components because it prevents a component from changing your model state except for the models that you explicitly pass in.

Note: Normally, a scope prototypically inherits from its parent. An isolated scope does not. See the “Isolating the Scope of a Directive” section for more information about isolate scopes.

Best Practice: Use the scope option to create isolate scopes when making components that you want to reuse throughout your app.

Creating a Directive that Manipulates the DOM

In this example we will build a directive that displays the current time. Once a second, it updates the DOM to reflect the current time.

Directives that want to modify the DOM typically use the link optionlink takes a function with the following signature,

function link(scope, element, attrs) { ... }

where:

  • scope is an Angular scope object.
  • element is the jqLite-wrapped element that this directive matches.
  • attrs is an object with the normalized attribute names and their corresponding values.

In our link function, we want to update the displayed time once a second, or whenever a user changes the time formatting string that our directive binds to. We will use the $interval service to call a handler on a regular basis. This is easier than using $timeout but also works better with end 2 end testing, where we want to ensure that all $timeouts have completed before completing the test. We also want to remove the $interval if the directive is deleted so we don’t introduce a memory leak.

Source

<!doctype html>
<html ng-app="docsTimeDirective">
  <head>
    <script src="http://code.angularjs.org/1.2.9/angular.min.js"></script>
    <script src="script.js"></script>
  </head>
  <body>
    <div ng-controller="Ctrl2">
      Date format: <input ng-model="format"> <hr/>
      Current time is: <span my-current-time="format"></span>
    </div>
  </body>
</html>
angular.module('docsTimeDirective', [])

.controller('Ctrl2', function($scope) {
	$scope.format = 'M/d/yy h:mm:ss a';
})

.directive('myCurrentTime', function($interval, dateFilter) {

	function link(scope, element, attrs) {
		var format, timeoutId;

		function updateTime() {
			element.text(dateFilter(new Date(), format));
		}

		scope.$watch(attrs.myCurrentTime, function(value) {
			format = value;
			updateTime();
		});

		element.on('$destroy', function() {
			$interval.cancel(timeoutId);
		});

		// start the UI update process; save the timeoutId for canceling
		timeoutId = $interval(function() {
			updateTime(); // update DOM
		}, 1000);
	}

	return {
		link : link
	};
});

Demo

Date format: 


Current time is: 1/21/14 4:30:05 PM

There are a couple of things to note here. Just like the module.controller API,  the function argument in module.directive is dependency injected. Because of this, we can use $interval and dateFilter inside our directive’s link function.

We register an event element.on('$destroy', ...). What fires this $destroy event?

There are a few special events that AngularJS emits. When a DOM node that has been compiled with Angular’s compiler is destroyed, it emits a $destroy event. Similarly, when an AngularJS scope is destroyed, it broadcasts a $destroy event to listening scopes.

By listening to this event, you can remove event listeners that might cause memory leaks. Listeners registered to scopes and elements are automatically cleaned up when they are destroyed, but if you registered a listener on a service, or registered a listener on a DOM node that isn’t being deleted, you’ll have to clean it up yourself or you risk introducing a memory leak.

Best Practice: Directives should clean up after themselves. You can use element.on('$destroy', ...) or scope.$on('$destroy', ...) to run a clean-up function when the directive is removed.

Creating a Directive that Wraps Other Elements

We’ve seen that you can pass in models to a directive using the isolate scope, but sometimes it’s desirable to be able to pass in an entire template rather than a string or an object. Let’s say that we want to create a “dialog box” component. The dialog box should be able to wrap any arbitrary content.

To do this, we need to use the transclude option.

Source

<!doctype html>
<html ng-app="docsTransclusionDirective">
<head>
<script src="http://code.angularjs.org/1.2.9/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body>
	<div ng-controller="Ctrl">
		<my-dialog>Check out the contents, {{name}}!</my-dialog>
	</div>
</body>
</html>
<div class="alert" ng-transclude>
</div>
angular.module('docsTransclusionDirective', [])
  .controller('Ctrl', function($scope) {
    $scope.name = 'Tobias';
  })
  .directive('myDialog', function() {
    return {
      restrict: 'E',
      transclude: true,
      templateUrl: 'my-dialog.html'
    };
  });

Demo

Check out the contents, Tobias!

What does this transclude option do, exactly? transclude makes the contents of a directive with this option have access to the scope outside of the directive rather than inside.

To illustrate this, see the example below. Notice that we’ve added a link function in script.js that redefines name as Jeff. What do you think the {{name}} binding will resolve to now?

Source

<!doctype html>
<html ng-app="docsTransclusionExample">
  <head>
    <script src="http://code.angularjs.org/1.2.9/angular.min.js"></script>
    <script src="script.js"></script>
  </head>
  <body>
    <div ng-controller="Ctrl">
      <my-dialog>Check out the contents, {{name}}!</my-dialog>
    </div>
  </body>
</html>
angular.module('docsTransclusionExample', [])
  .controller('Ctrl', function($scope) {
    $scope.name = 'Tobias';
  })
  .directive('myDialog', function() {
    return {
      restrict: 'E',
      transclude: true,
      scope: {},
      templateUrl: 'my-dialog.html',
      link: function (scope, element) {
        scope.name = 'Jeff';
      }
    };
  });

Demo

Check out the contents, Tobias!

Ordinarily, we would expect that {{name}} would be Jeff. However, we see in this example that the {{name}}binding is still Tobias.

The transclude option changes the way scopes are nested. It makes it so that the contents of a transcluded directive have whatever scope is outside the directive, rather than whatever scope is on the inside. In doing so, it gives the contents access to the outside scope.

Note that if the directive did not create its own scope, then scope in scope.name = 'Jeff'; would reference the outside scope and we would see Jeff in the output.

This behavior makes sense for a directive that wraps some content, because otherwise you’d have to pass in each model you wanted to use separately. If you have to pass in each model that you want to use, then you can’t really have arbitrary contents, can you?

Best Practice: only use transclude: true when you want to create a directive that wraps arbitrary content.

Next, we want to add buttons to this dialog box, and allow someone using the directive to bind their own behavior to it.

Source

<!doctype html>
<html ng-app="docsIsoFnBindExample">
<head>
<script src="http://code.angularjs.org/1.2.9/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body>
	<div ng-controller="Ctrl">
		<my-dialog ng-hide="dialogIsHidden" on-close="hideDialog()">
		Check out the contents, {{name}}! 
		</my-dialog>
	</div>
</body>
</html>
<div class="alert">
  <a href class="close" ng-click="close()">×</a>
  <div ng-transclude></div>
</div>
angular.module('docsIsoFnBindExample', [])
  .controller('Ctrl', function($scope, $timeout) {
    $scope.name = 'Tobias';
    $scope.hideDialog = function () {
      $scope.dialogIsHidden = true;
      $timeout(function () {
        $scope.dialogIsHidden = false;
      }, 2000);
    };
  })
  .directive('myDialog', function() {
    return {
      restrict: 'E',
      transclude: true,
      scope: {
        'close': '&onClose'
      },
      templateUrl: 'my-dialog-close.html'
    };
  });

Demo

×

Check out the contents, Tobias!

We want to run the function we pass by invoking it from the directive’s scope, but have it run in the context of the scope where its registered.

We saw earlier how to use =attr in the scope option, but in the above example, we’re using &attr instead. & bindings expose a function to an isolated scope allowing the isolated scope to invoke it, but maintaining the original scope of the function. So when a user clicks the x in the dialog, it runs Ctrl‘s hideDialog function.

Best Practice: use &attr in the scope option when you want your directive to expose an API for binding to behaviors.

Creating a Directive that Adds Event Listeners

Previously, we used the link function to create a directive that manipulated its DOM elements. Building upon that example, let’s make a directive that reacts to events on its elements.

For instance, what if we wanted to create a directive that lets a user drag an element?

Source

<!doctype html>
<html ng-app="dragModule">
  <head>
    <script src="http://code.angularjs.org/1.2.9/angular.min.js"></script>
    <script src="script.js"></script>
  </head>
  <body>
    <span my-draggable>Drag ME</span>
  </body>
</html>
angular.module('dragModule', []).
  directive('myDraggable', function($document) {
    return function(scope, element, attr) {
      var startX = 0, startY = 0, x = 0, y = 0;

      element.css({
       position: 'relative',
       border: '1px solid red',
       backgroundColor: 'lightgrey',
       cursor: 'pointer'
      });

      element.on('mousedown', function(event) {
        // Prevent default dragging of selected content
        event.preventDefault();
        startX = event.pageX - x;
        startY = event.pageY - y;
        $document.on('mousemove', mousemove);
        $document.on('mouseup', mouseup);
      });

      function mousemove(event) {
        y = event.pageY - startY;
        x = event.pageX - startX;
        element.css({
          top: y + 'px',
          left:  x + 'px'
        });
      }

      function mouseup() {
        $document.unbind('mousemove', mousemove);
        $document.unbind('mouseup', mouseup);
      }
    }
  });

Creating Directives that Communicate

You can compose any directives by using them within templates.

Sometimes, you want a component that’s built from a combination of directives.

Imagine you want to have a container with tabs in which the contents of the container correspond to which tab is active.

Source

<!doctype html>
<html ng-app="docsTabsExample">
  <head>
    <script src="http://code.angularjs.org/1.2.9/angular.min.js"></script>
    <script src="script.js"></script>
  </head>
  <body>
    <my-tabs>
      <my-pane title="Hello">
        <h5 id="creating-custom-directives_source_hello">Hello</h5>
        <p>Lorem ipsum dolor sit amet</p>
      </my-pane>
      <my-pane title="World">
        <h5 id="creating-custom-directives_source_world">World</h5>
        <em>Mauris elementum elementum enim at suscipit.</em>
        <p><a href ng-click="i = i + 1">counter: {{i || 0}}</a></p>
      </my-pane>
    </my-tabs>
  </body>
</html>
<div class="tabbable">
  <ul class="nav nav-tabs">
    <li ng-repeat="pane in panes" ng-class="{active:pane.selected}">
      <a href="" ng-click="select(pane)">{{pane.title}}</a>
    </li>
  </ul>
  <div class="tab-content" ng-transclude></div>
</div>
<div class="tab-pane" ng-show="selected" ng-transclude>
</div>
angular.module('docsTabsExample', [])
  .directive('myTabs', function() {
    return {
      restrict: 'E',
      transclude: true,
      scope: {},
      controller: function($scope) {
        var panes = $scope.panes = [];
 
        $scope.select = function(pane) {
          angular.forEach(panes, function(pane) {
            pane.selected = false;
          });
          pane.selected = true;
        };
 
        this.addPane = function(pane) {
          if (panes.length == 0) {
            $scope.select(pane);
          }
          panes.push(pane);
        };
      },
      templateUrl: 'my-tabs.html'
    };
  })
  .directive('myPane', function() {
    return {
      require: '^myTabs',
      restrict: 'E',
      transclude: true,
      scope: {
        title: '@'
      },
      link: function(scope, element, attrs, tabsCtrl) {
        tabsCtrl.addPane(scope);
      },
      templateUrl: 'my-pane.html'
    };
  });

The myPane directive has a require option with value ^myTabs. When a directive uses this option, $compile will throw an error unless the specified controller is found. The ^ prefix means that this directive searches for the controller on its parents (without the ^ prefix, the directive would look for the controller on just its own element).

So where does this myTabs controller come from? Directives can specify controllers using the unsurprisingly named controller option. As you can see, the myTabs directive uses this option. Just like ngController, this option attaches a controller to the template of the directive.

Looking back at myPane‘s definition, notice the last argument in its link function: tabsCtrl. When a directive requires a controller, it receives that controller as the fourth argument of its link function. Taking advantage of this,myPane can call the addPane function of myTabs.

Savvy readers may be wondering what the difference is between link and controller. The basic difference is that controller can expose an API, and link functions can interact with controllers using require.

Best Practice: use controller when you want to expose an API to other directives. Otherwise use link.

Summary

Here we’ve seen the main use cases for directives. Each of these samples acts as a good starting point for creating your own directives.

You might also be interested in an in-depth explanation of the compilation process that’s available in the compiler guide.

The $compile API page has a comprehensive list of directive options for reference.

AngularJS: Things I Wish I Were Told About Angular.js

[Fuente: http://ruoyusun.com/2013/05/25/things-i-wish-i-were-told-about-angular-js.html]

25 May 2013

Recently I have worked on a project using Angular.js. As of writing this post, it’s a medium sized app (~10 modules, ~20 controllers, ~5 services and ~10 directives) with quite decent test coverage. When I look back, I find myself learning much more about Angular.js than before. It’s not a smooth ride: I’ve gone through lots of refactor and rewrite. And there are lots of things I wish I were told before I started to work on Angular.js

Heads up! The post is based on Angular.js stable branch (1.0.x). Some of the content might not apply if you choose to live on the edge (1.1.x).

About Learning Curve

Angular.js has a very different learning curve from Backbone.js. Backbone.js has a steep learning curve up front: to write a simplest app, you need to know pretty much everything about it. And after you have nailed it, there is pretty much nothing other than some common building blocks and best practices.

However, Angular.js is very different. The initial barrier to get started is very low: after going through the examples on homepage, you should be good to go. You don’t need to understand all core concepts like module, service, dependency injection, scope. Controller and some directives can get you started. And the documentation for quick start is good enough.

The problem is when you dive into Angular.js and start to write some serious app, the learning curve suddenly becomes very steep and its documentations are either incomplete or cumbersome. It took quite some time to get over this stage and started to benefit from all these learning. This is the first thing I wish I were told – so that I would not feel frustrated when I had all these problems.

Understand Modules Before You Start

Angular.js does not force you to use its module system. So when I started, I had a huge CoffeeScript file with lots of controllers with no segregation. It soon went out of control: it’s almost impossible to navigate the file and you have to load this huge file for every page even if you are using only one of the controllers.

So I had to stop and refactor my code. I first split controllers into different modules based on different pages and then extract some common filters and services. Then I made sure all modules had its dependencies set up correctly and components are successfully injected. Of course, you also need to understand dependency injection (DI): a concept that is quite popular in Java and C# world but not in dynamic languages. Fortunately (or some of you may think it’s unfortunate), I’ve done quite some Java and C#, it did not took me very long to understand DI in Angular.js – although it did not feel natural to use DI in JavaScript for the first time. When you get used to DI, you will love the concept, it makes your code less coupled and easier to maintain.

So if you do not want to go through the refactor, learn and plan your modules before you start.

When Your Controllers Get Bigger, Learn Scope

I am sure you use $scope at the very beginning, but probably not understand it. Well, you don’t need to. You can treat it as magic. However, here are some very common questions you might have encountered:

Why my view will not get updated?

function SomeCtrl($scope) {
	setTimeout(function() {
		$scope.message = "I am here!";
	}, 1000);
}

Why ng-model="touched" does not work as expected?

function SomeCtrl($scope) {
	$scope.items = [{ value: 2 }];
	$scope.touched = false;
}
<ul>
	<li ng-repeat="item in items">
		<input type="text" ng-model="item.value">
		<input type="checkbox" ng-model="touched">
	</li>	
</ul>

These all have something to do with $scope. But more importantly, when your controllers get bigger and bigger, it’s time to break it into sub controllers, and inheritance is closely related to $scope. You need to understand how $scope works:

  1. How the magical data bindings is related to $scope.$watch() and $scope.$apply();
  2. How the $scope is shared between a controller and its child;
  3. When Angular.js will implicitly create a new $scope;
  4. How the events ($scope.$on$scope.$emit$scope.$broadcast work as a communication among scopes)

FYI, the answer to the two questions above are: for 1, you need $scope.$apply() and for 2, Angular.js creates a scope implicitly in ng-repeat.

When You Manipulate DOM in Controller, Write Directives

Angular.js advocates separation of controller and view (DOM). But there are cases when you might need access to DOM in controllers. A typical example is jQuery plugins. Although jQuery plugins seem a little bit “outdated”, but the ecosystem is not going away any sooner. However, it’s really a bad idea to use jQuery plugin directly in your controller: you are making your controller impossible to test and you can hardly reuse any logic.

The best way to deal with it is writing your own directive. I am sure you’ve used directives, but you might not think you can write one. In fact, directives are one of the most powerful concepts in Angular.js. Think of it as reusable components: not only for jQuery plugins, but also for any of your (sub) controllers that get used in multiple places. It’s kinda like shadow DOM. And the best part is, your controller does not need to know the existence of directives: communications are achieved through scope sharing and $scope events.

However, the documentation on directives is probably one of the worst Angular.js documentations. It’s full of jargon, with very few examples and lots of abstract explanations without any context. So don’t freak out if you cannot understand it. The way I get over this is to start writing directives, even without fully understand the documentations. When I reach a stage where I don’t know what to do, I go back to the documentation or Google around. After finishing wrapping a jQuery plugin into my own directive, I master most of the concepts. Learning by doing is probably the most efficient way when there is no good documentation.

For any of you who look for a word of wisdom, here is my one sentence summary: put control logic in directive controller, and DOM logic in link function; scope sharing is the glue.

Angular.js Router Might Not Be What You Expected

This is one of the gotchas that takes me some time of figure out. Angular.js router has a very specific usage. It’s not like Backbone.js router where it monitors the location.hash and call a function when the route matches. Angular.js works like server-side router: it is built to work with ng-view. When a route is hit, a template is loaded and injected into ng-view and some controller can be instantiated. So if you don’t like this behavior, you have to roll out your own service (wrap some existing library into a Angular.js service).

This is not a generic tips, rather, it is very specific. However, I wasted lots of time on this so I just put it here and it might save you a few hours.

About Testing

Since Angular.js advocates separation of view and controller. Writing unit tests on controller is very easy: no DOM is needed at all. Again, the purpose of unit test is not to guarantee that your app runs without a problem – that’s the purpose of integration tests. Unit tests are used to quickly locate the buggy code when your integration tests fail. The only unit test that requires some DOM manipulation is directive.

Because there is dependency injection, when writing your controller unit tests, you can easily use a mock for one of the dependencies, which makes assertions much easier. A typically way to do this is use a mock when instantiate your controller. Or since Angular.js DI uses last win rule, you can rebind (override) your dependency by registering a fake implementation in the tests.

Angular.js also have a E2E test, which might not be easy to setup and run, especially your page is rendered by some server-side language first before JavaScript takes control. After spending quite some time on setting this up, I eventually gave up and fell back using Selenium tests as a higher level of integration tests.

Although I have been using Angular.js a lot lately, I cannot call myself an expert. In fact, one of the reason I write this post is also to learn: I will appreciated it if you can correct my mistakes or misunderstandings. Please Discuss on HN

If you have comment, you can post it HN (link can be found at the end of the essay), send me an email at ruoysun AT gmail DOT com or ping me on Twitter @insraq.

 

Angular JS Book: Chapter 7: Otros aspectos

[Fuente: AngularJS book by Brad Green and Shyam Seshadri]

In this chapter, we will take a look at some other useful features that are present in AngularJS, but weren’t covered at all or in depth in the chapters and examples so far.

$location

Up to now, you have seen quite a few examples of the $location service in AngularJS.Most of them would have been fleeting glances—an access here, set there. In this section,we will dive into what exactly the $location service in AngularJS is for, and when you should and shouldn’t use it.

The $location service is a wrapper around the window.location that is present in any browser. So why would you want to use it instead of working directly with window.location?

  • Goodbye global state : window.location is a prime example of global state (actually, both window and document objects in the browser are prime examples). The minute you have global state in your application, testing, maintaining and working with it becomes a hassle (if not now, then definitely in the long run). The $location service hides this nastiness (what we call global state), and allows you to test the browser’s location details by injecting mocks during your unit tests.
  • API: window.location gives you total access to the contents of the browser location.That is, window.location gives you the string while $location gives you nice,jQuery-like setters and getters to work with it in a clean way.
  • AngularJS integration:If you use $location, you can use it however you want. But with window.location, you would have to be responsible for notifying AngularJS of changes, and listen to changes as well.
  • HTML5 integration:The $location service is smart enough to realize when HTML5 APIs are available within a browser and use them. If they’re not available, it will fall back to the default usage.

So when should you use the $location service? Any time you want to react to a change in the URL (that is not covered by the $routes, which you should primarily use for working with URL-based views), as well as effect a change in the current URL in the browser.

Let’s consider a small example of how you would use the $location service in a realworld application. Consider a case where we have a datepicker, and when a date is selected, the app navigates to a certain URL. Let us take a look at how that might look:

// Assume that the datepicker calls $scope.dateSelected with the date
$scope.dateSelected = function(dateTxt) {
  $location.path('/filteredResults?startDate=' + dateTxt);
  // If this were being done in the callback for
  // an external library, like jQuery, then we would have to
  $scope.$apply();
};

——

*NOTA: To $apply, or Not to $apply?

There is confusion amongst AngularJS developers about when $scope.$apply() should be called and when it shouldn’t.Recommendations and rumors on the Internet are rampant. This section will make it crystal clear.

But first, let us try to put $apply in a simpler form.

Scope.$apply is like a lazy worker. It is told to do a lot of work, and it is responsible for making sure that the bindings are updated and the view reflects all those changes. But rather than doing this work all the time, it does it only when it feels it has enough work to be done. In all other cases, it just nods, and notes the work for later. It only actually does the work when you get its attention and tell it explicitly to work. AngularJS does this internally at regular intervals within its lifecycle, but if the call comes from outside (say a jQuery UI event), scope.$apply just takes note, but does nothing. That is why we have to call scope.$apply to tell it, “Hey! You need to do this right now, and not wait!”

Here are four quick tips about when (and how) to call $apply.

  • DO NOT call it all the time. Calling $apply when AngularJS is happily ticking away (in its $digest cycle, as we call it) will cause an exception. So “better safe than sorry” is not the approach you want to use.
  • DO CALL it when controls outside of AngularJS (DOM events, external callbacks such as jQuery UI controls, and so on) are calling AngularJS functions. At that point, you want to tell AngularJS to update itself (the models, the views, and so on), and $apply does just that.
  • Whenever possible, execute your code or function by passing it to $apply, rather than executing the function and then calling $apply(). For example, execute the following code:
$scope.$apply(function() {
  $scope.variable1 = 'some value';
  executeSomeAction();
});
instead of the following:
$scope.variable1 = 'some value';
executeSomeAction();
$scope.$apply();

While both of these will have the same effect, they differ in one significant way.The first will capture any errors that happen when executeSomeAction is called, while the latter will quietly ignore any such errors. You will get error notifications from AngularJS only when you do the first.

  • Consider using something like safeApply:
$scope.safeApply = function(fn) {
  var phase = this.$root.$$phase;
  if(phase == '$apply' || phase == '$digest') {
    if(fn && (typeof(fn) === 'function')) {
      fn();
    }
  } else {
    this.$apply(fn);
  }
};

You can monkey patch this into the topmost scope or the rootscope, and then use the $scope.$safeApply function everywhere. This has been under discussion, and hopefully in a future release, this will be the default behavior.

—-

What are those other methods also available on the $location object? Table 7-1 contains a quick summary for you to use in a bind.

Let us take a look at how the $location service would behave, if the URL in the browser was

http://www.host.com/base/index.html#!/path?param1=value1#hashValue.

Table 7-1. Functions on the $location service
Getter Function –> Getter Value –> Setter Function

  • absUrl() –> http://www.host.com/base/index.html#!/path?param1=value1#hashValue  –> N/A
  • hash() –> hashValue –> hash(‘newHash’)
  • host() –> www.host.com –> N/A
  • path() –> /path –> path(‘/newPath’)
  • protocol() –> http –> N/A
  • search()  –> {‘param1’: ‘value1‘} –> search({‘c’: ‘def’})
  • url() —> /path?param1=value1?hashValue –> url(‘/newPath?p2=v2’)

The Setter Function column in Table 7-1 has some sample values that denote the type of object the setter function expects.

Note that the search() setter has a few modes of operation:

  • Calling search(searchObj) with an object<string, string> basically denotes all the parameters and their values
  • Calling search(string) will set the URL params as q=String directly in the URL
  • Calling search(param, value) with a string and value sets (or calling with null removes) a particular search parameter in the URL Using any one of the setters does not mean that window.location will get changed instantly!

The $location service plays well with the Angular lifecycle, so all changes to the location will accumulate and get applied together at the end of the cycle. So feel free to make those changes, one after the other, without fear that the user will see a URL that keeps flickering and changing underneath him.

HTML5 Mode and Hashbang Mode

The $location service can be configured using the $locationProvider (which can be injected, just like everything else in AngularJS). Of particular interest are two properties on this provider, which are:

  • html5ModeA boolean value which dictates whether the $location service works in HTML5 mode or not
  • hashPrefixA string value (actually a single character) that is used as the prefix for Hashbang URLs (in Hashbang mode or legacy browsers in HTML5 mode). By default it is empty, so Angular’s hash is just ‘’. If the hashPrefix is set to ‘!’, then Angular uses what we call Hashbang URLs (! followed by the url).

You might ask, just what are these modes? Well, pretend that you have this super awesome website at www.superawesomewebsite.com that uses AngularJS.

Let’s say you have a particular route (with some parameters and a hash), such as /foo?bar=123#baz.

In normal Hashbang mode (with the hashPrefix set to ‘!’), or in legacy browsers without HTML5 mode support, your URL would look something like:

http://www.superawesomewebsite.com/#!/foo?bar=123#baz

While in HTML5 mode, the URL would simply look like this:

http://www.superawesomewebsite.com/foo?bar=123#baz

In both cases, location.path() would be /foo, location.search() would be bar=123, and location.hash() would be baz. So if that is the case, why wouldn’t you want to use the HTML5 mode?

The Hashbang approach works seamlessly across all browsers, and requires the least amount of configuration. You just need to set the hashBang prefix (! by default) and you are good to go.

The HTML5 mode, on the other hand, talks to the browser URL through the use of HTML5 History API. The $location service is smart enough to figure out whether HTML5 mode is supported or not, and fall back to the Hashbang approach if necessary, so you don’t need to worry about additional work. But you do have to take care of the following:

Server-side configuration
Because HTML5 links look like any other URL on your application, you need to take care on the server side to route all links within your app to your main HTML (most likely, the index.html). For example, if your app is the landing page for superawesomewebsite.com, and you have a route /amazing?who=me in your app, then the URL that the browser would show is

http://www.superawesomewebsite.com/amazing?who=me+.

When you browse through your app, this will be fine, as the HTML5 History API kicks in and takes care of things. But if you try to browse directly to this URL, your server will look at you as if you have gone crazy, as there is no such known resource on its side. So you would have to ensure that all requests to /amazing get redirected to /index.html#!/amazing.

AngularJS will kick in from that point onward and take care of things. It will detect changes to the path and redirect to the correct AngularJS routes that were defined.

Link rewriting
You can easily specify URLs as follows:

<a href="/some?foo=bar">link</a>

Depending on whether you are using HTML5 mode or not, AngularJS will take care to redirect to /some?foo=bar or index.html#!/some?foo=bar, respectively. No additional steps are required on your part. Awesome, isn’t it?

But the following types of links will not be rewritten, and the browser will perform a full reload on the page:

a.Links that contain a target element such as the following:

<a href="/some/link" target="_self">link</a>

b. Absolute links going to a different domain:

<a href="http://www.angularjs.org">link</a>

This is different because it is an absolute URL, while the previous example used the existing base URL.

c. Links starting with a different base path when one is already defined:

<a href="/some-other-base/link">link</a>

Relative Links
Be sure to check all relative links, images, scripts, and so on. You must either specify the URL base in the head of your main HTML file (<base href=”/my-base”>), or you must use absolute URLs (starting with /) everywhere because relative URLs will be resolved to absolute URLs using the initial absolute URL of the document, which is often different from the root of the application.

Running Angular apps with the History API enabled from document root is strongly encouraged, as it takes care of all relative link issues.

AngularJS Module Methods

The AngularJS Module is responsible for defining how your application is bootstrapped.It also declaratively defines the pieces of your application. Let us take a look at how itaccomplishes this.

Where’s the Main Method?

Those of you coming from a programming language like Java or even Python might be wondering, where is that main method in AngularJS? You know, the one that bootstraps everything, and is the first thing to get executed? The one that functions in JavaScript and instantiates and wires everything together, then tells your application to go run?

AngularJS doesn’t have that. What it has instead is the concept of modules. Modules allow us to declaratively specify our application’s dependencies, and how the wiring and bootstrapping happens. The reason for this kind of approach is manifold:

  1. It is declarative. That means it is written in a way that is easier to write and understand.It reads like English!
  2. It is modular. It forces you to think about how you define your components and dependencies, and makes them explicit.
  3. It allows for easy testing. In your unit tests, you can selectively pull in modules, and avoid the untestable portions of your code. And in your scenario tests, you can load additional modules, which can make working with some components easier.

Let us first take a look at how you would use a module that you have defined, then take a look at how we would declare one.

Say we have a module, in fact, the module for our application, called “MyAwesomeApp.”In my HTML, I could just add the following to the <html> tag (or technically, any other tag):

<html ng-app="MyAwesomeApp">

The ng-app directive tells AngularJS to bootstrap your application using the MyAwesomeApp module.

So how would that module be defined? Well, for one, we recommend that you have separate modules for your services, directives, and filters. Your main module could then just declare the other modules as a dependency (just like we did in Chapter 4 with the RequireJS example).

This makes it easier to manage your modules, as they are nice complete chunks of code.Each module has one and only one responsibility. This also allows your tests to load only the modules they care about, and thus reduces the amount of initialization that needs to happen. The tests can be small and focused.

Loading and Dependencies

Module loading happens in two distinct phases, and the functions reflect them. These are the Config and the Run blocks (or phases):

The Config block
AngularJS hooks up and registers all the providers in this phase. Because of this, only providers and constants can be injected into Config blocks. Services that may or may not have been initialized cannot be injected.

The Run block
Run blocks are used to kickstart your application, and start executing after the injector is finished creating. To prevent further system configuration from happening from this point onwards, only instances and constants can be injected into Run blocks. The Run block is the closest you are going to find to a main method in AngularJS.

Convenience Methods

What can you do with a module? We can instantiate controllers, directives, filters, and services, but the module class allows you to do more, as you can see in Table 7-2:
Table 7-2. Module configuration methods
API Method –> Description

  • config(configFn) –> Use this method to register work that needs to be done when the module is loading.
  • constant(name, object) This happens first, so you can declare all your constants app-wide, and have them available at all configuration (the first method in this list) and instance methods (all methods from here on, like controller, service, and so on).
  • controller(name, constructor) We have seen a lot of examples of this; it basically sets up a controller for use.
  • directive(name, directiveFactory) As discussed in Chapter 6, this allows you to create directives within your app.
  • filter(name, filterFactory) Allows you to create named AngularJS filters, as discussed in previous chapters.
  • run(initializationFn) Use this method when you want to perform work that needs to happen once the injector is set up, right before your application is available to the user.
  • value(name, object) Allows values to be injected across the application.
  • service(name, serviceFactory) Covered in the next section.
  • factory(name, factoryFn) Covered in the next section.
  • provider(name, providerFn) Covered in the next section.

You might realize that we are missing the details of three particular API calls—Factory,Provider, and Service—from the preceding table. There is a reason for that: it is quite easy to confuse the usage between the three, so we will dive into a small example that should better illustrate when (and how!) to use each one.

The Factory
The Factory API call is used whenever we have a class or object that needs some amount of logic or parameters before it can be initialized. A Factory is a function that is responsible for creating a certain value (or object). Let us take the example of a greeter function that needs to be initialized with its salutation:

function Greeter(salutation) {
	this.greet = function(name) {
		return salutation + ' ' + name;
	};
}

The greeter factory would look something like:

myApp.factory('greeter', function(salut) {
  return new Greeter(salut);
});

and it would be called as:

var myGreeter = greeter('Halo');

Another simpler example:

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

// Factory
app.factory('testFactory', function(){
    return {
        sayHello: function(text){
            return "Factory says \"Hello " + text + "\"";
        }  
    }               
});

// AngularJS Controller that uses the factory
function HelloCtrl($scope, testFactory)
{
    $scope.fromFactory = testFactory.sayHello("World");
}

The Service
What about services? Well, the difference between a Factory and a Service is that the Factory invokes the function passed to it and returns a result. The Service invokes “new” on the constructor method passed to it and returns the result.

So the preceding greeter Factory could be replaced with a greeter Service as follows:

myApp.service('greeter', Greeter);

Every time I asked for a greeter, AngularJS would call the new Greeter() and return that.

Another simpler example:

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

// Service definition
app.service('testService', function(){
    this.sayHello= function(text){
        return "Service says \"Hello " + text + "\"";
    };        
});

// AngularJS Controller that uses the service
function HelloCtrl($scope, testService)
{
    $scope.fromService = testService.sayHello("World");
}

The Provider
This is the most complicated (and thus most configurable, obviously) of the lot.The Provider combines both the Factory and the Service, and also throws in the benefit of being able to configure the Provider function before the injection system is fully in place (in the config blocks, that is).

Let’s see how a modified greeter Service using the Provider might look:

myApp.provider('greeter', function() {
  var salutation = 'Hello';
  this.setSalutation = function(s) {
    salutation = s;
  }
  function Greeter(a) {
    this.greet = function() {
      return salutation + ' ' + a;
    }
  }
  this.$get = function(a) {
    return new Greeter(a);
  };
});

This allows us to set the salutation at runtime (for example, based on the language of the user).

var myApp = angular.module(myApp, []).config(function(greeterProvider) {
  greeterProvider.setSalutation('Namaste');
});

AngularJS would internally call $get whenever someone asked for an instance of the greeter object.
* Warning!
There is a slight, but significant difference between using:
angular.module(‘MyApp’, […])
and:
angular.module(‘MyApp’)

The difference is that the first creates a new Angular module, pulling in the module dependencies listed in the square brackets ([…]). The second uses the existing module that has already been defined by the first call.

So you should make sure that you use the following code only once in your entire application:
angular.module(‘MyApp’, […]) // Or MyModule, if you are modularizing your app

If you do not plan to save it to a variable and refer to it across your application, then use angular.module(MyApp) in the rest of the files to ensure you get a handle to the correct AngularJS module. Everything on the module must be defined by accessing the variable, or be added on the spot where the module has been defined.

Communicating Between Scopes with $on,$emit, and $broadcast

AngularJS scopes have a very hierarchical and nested structure. There is one main $rootScope (per Angular app or ng-app, that is), which all other scopes either inherit, or are nested under. Quite often, you will find that scopes don’t share variables or do not prototypically inherit from one another.

In such a case, how do you communicate between scopes? One option is creating a service that is a singleton in the scope of the app, and processing all inter-scope communication through that service.

There is another option in AngularJS: communicating through events on the scope.There are some restrictions; for example, you cannot generally broadcast an event to all watching scopes. You have to be selective in whether you are communicating to your parents or to your children.

But before we discuss that, how do you listen to these events? Here is an example where our scope on any Star System is waiting and watching for an event we call “planetDestroyed.”

scope.$on('planetDestroyed', function(event, galaxy, planet) {
  // Custom event, so what planet was destroyed
  scope.alertNearbyPlanets(galaxy, planet);
});

Where do these additional arguments to the event listener come from? Let’s take a look at how an individual planet could communicate with its parent Star System.

scope.$emit('planetDestroyed’, scope.myGalaxy, scope.myPlanet);

The additional arguments to $emit are passed on as function parameters to the listener functions. Also, $emit communicates only upwards from its current scope, so the poor denizens of the planet (if they had a scope to themselves) would not be notified if their planet was being destroyed.

Similarly, if a Galaxy wanted to communicate downwards to its child, the Star System scope, then it could communicate as follows:

scope.$emit('selfDestructSystem', targetSystem);

Then all Star Systems listening for the event could look at the target system, and decide if they should self-destruct, using these commands:

scope.$on('selfDestructSystem', function(event, targetSystem) {
  if (scope.mySystem === targetSystem) {
    scope.selfDestruct(); // Go Ka-boom!!
  }
});

Of course, as the event propagates all the way up (or down), it might become necessary at a certain level or scope to say, “Enough! You shall not PASS!” or to prevent what the event does by default. The event object passed to the listener has functions to handle all of the above, and more, so let us take a quick look at what you can get up to with the event object in Table 7-3.

Table 7-3. Event object properties and methods
Property of event –> Purpose

  • event.targetScope –> The scope which emitted or broadcasted the event originally
  • event.currentScope –> The scope currently handling the event
  • event.name –> The name of the event
  • event.stopPropagation() –> A function which will prevent further event propagation (this is available only for events that were $emitted 
  • event.preventDefault() –> This actually doesn’t do anything but set defaultPrevented to true. It is up to the implementer of the listeners to check on defaultPrevented before taking action 
  • event.defaultPrevented –> true if preventDefault was called

fd
fd
fd
fd
ff
f

Qué es el Scrum

Fuente: http://www.proyectosagiles.org/que-es-scrum

Scrum es un proceso en el que se aplican de manera regular un conjunto de mejores prácticas para trabajar colaborativamente, en equipo, y obtener el mejor resultado posible de un proyecto. Estas prácticas se apoyan unas a otras y su selección tiene origen en un estudio de la manera de trabajar de equipos altamente productivos.

En Scrum se realizan entregas parciales y regulares del producto final, priorizadas por el beneficio que aportan al receptor del proyecto. Por ello, Scrum está especialmente indicado para proyectos en entornos complejos, donde se necesita obtener resultados pronto, donde los requisitos son cambiantes o poco definidos, donde la innovación, la competitividad, la flexibilidad y la productividad son fundamentales.

Scrum también se utiliza para resolver situaciones en que no se está entregando al cliente lo que necesita, cuando las entregas se alargan demasiado, los costes se disparan o la calidad no es aceptable, cuando se necesita capacidad de reacción ante la competencia, cuando la moral de los equipos es baja y la rotación alta, cuando es necesario identificar y solucionar ineficiencias sistemáticamente o cuando se quiere trabajar utilizando un proceso especializado en el desarrollo de producto.

Historia

En 1986 Hirotaka Takeuchi e Ikujiro Nonaka describieron una nueva aproximación holística que incrementa la rapidez y la flexibilidad en el desarrollo de nuevos productos comerciales.[1]Takeuchi y Nonaka comparan esta nueva aproximación holística, en la cual las fases se traslapan de manera intensa y el proceso completo es realizado por un equipo con funciones transversales, como en el rugby, donde los 8 delanteros del equipo «actúan como una unidad para intentar desplazar a los fowards del equipo contrario». Los casos de estudio provienen de las industrias automovilísticas, así como de fabricación de máquinas fotográficas, computadoras e impresoras.

En 1991 Peter DeGrace y Leslie Stahl en su libro Wicked Problems, Righteous Solutions (A problemas malvados, soluciones virtuosas),[2] se refirieron a esta aproximación como scrum (melé en inglés), un término propio del rugby mencionado en el artículo por Takeuchi y Nonaka.

A principios de los años 1990 Ken Schwaber empleó una aproximación que lo llevó a poner en práctica el scrum en su compañía, Advanced Development Methods.[cita requerida] Por aquel tiempo Jeff Sutherland desarrolló una aproximación similar en Easel Corporation y fue el primero en denominar scrum. En 1995 Schwaber y Sutherland, durante el OOPSLA ’95 desarrollado en Austin, presentaron en paralelo una serie de artículos describiendo scrum, siendo ésta la primera aparición pública de la metodología.[cita requerida] Durante los años siguientes,Schwaber y Sutherland, colaboraron para consolidar los artículos antes mencionados, así como sus experiencias y el conjunto de mejores prácticas de la industria que conforman a lo que ahora se le conoce como scrum.[cita requerida] En 2001, Schwaber y Mike Beedle describieron la metodología en el libro Agile Software Development with Scrum.

El proceso

En Scrum un proyecto se ejecuta en bloques temporales cortos y fijos (iteraciones de un mes natural y hasta de dos semanas, si así se necesita). Cada iteración tiene que proporcionar un resultado completo, un incremento de producto final que sea susceptible de ser entregado con el mínimo esfuerzo al cliente cuando lo solicite.

El proceso parte de la lista de objetivos/requisitos priorizada del producto, que actúa como plan el proyecto. En esta lista el cliente prioriza los objetivos balanceando el valor que leaportan respecto a su coste y quedan repartidos en iteraciones y entregas. De manera regular el cliente puede maximizar la utilidad de lo que se desarrolla y el retorno de inversiónmediante la replanificación de objetivos que realiza al inicio de cada iteración.

Las actividades que se llevan a cabo en Scrum son las siguientes:

Planificación de la iteración

El primer día de la iteración se realiza la reunión de planificación de la iteración. Tiene dos partes:

  1. Selección de requisitos (4 horas máximo). El cliente presenta al equipo la lista de requisitos priorizada del producto o proyecto.El equipo pregunta al cliente las dudas que surgen y selecciona los requisitos más prioritarios que se compromete a completar en la iteración, de manera que puedan ser entregados si el cliente lo solicita.
  2. Planificación de la iteración (4 horas máximo). El equipo elabora la lista de tareas de la iteración necesarias para desarrollar los requisitos a que se ha comprometido. La estimaciónde esfuerzo se hace de manera conjunta y los miembros del equipo se autoasignan las tareas.

Ejecución de la iteración

Cada día el equipo realiza una reunión de sincronización (15 minutos máximo). Cada miembro del equipo inspecciona el trabajo que el resto está realizando (dependencias entre tareas,progreso hacia el objetivo de la iteración,  obstáculos que pueden impedir este objetivo) para poder hacer las adaptaciones necesarias que permitan cumplir con el compromiso adquirido. En la reunión cada miembro del equipo responde a tres preguntas:

  • ¿Qué he hecho desde la última reunión de sincronización?
  • ¿Qué voy a hacer a partir de este momento?
  • ¿Qué impedimentos tengo o voy a tener?

Durante la iteración el Facilitador se encarga de que el equipo pueda 

cumplir con su compromiso y de que no se merme su productividad.

Elimina los obstáculos que el equipo no puede resolver por sí mismo.

Protege al equipo de interrupciones externas que puedan afectar su compromiso o su productividad.

Inspección y adaptación

El último día de la iteración se realiza la reunión de revisión de la iteración. Tiene dos partes:

  1. Demostración (4 horas máximo). El equipo presenta al cliente los requisitos completados en la iteración, en forma de incremento de producto preparado para ser entregado con el mínimo esfuerzo. En función de los resultados mostrados y de los cambios que haya habido en el contexto del proyecto, el cliente realiza las adaptaciones necesarias de manera objetiva, ya desde la primera iteración, replanificando el proyecto.
  2. Retrospectiva (4 horas máximo). El equipo analiza cómo ha sido su manera de trabajar y cuáles son los problemas que podrían impedirle progresar adecuadamente, mejorando de manera continua su productividad. El Facilitador se encargará de ir eliminando los obstáculos identificados.

AngularJS Book: Chapter 6: Directives

With directives, you can extend HTML to add declarative syntax to do whatever you like. By doing so, you can replace generic <div>s and <span>s with elements and attributes that actually mean something specific to your application. The ones that come with Angular provide basic functionality, but you can create your own to do things
specific to your application.

First we’re going to go over the directives API and how it fits within the Angular startup and runtime lifecycles. From there, we’ll use this knowledge to create several classes of directives. We’ll finish the chapter with how to write unit tests for directives and how to make these run quickly.

But first, a few notes on the syntax for using directives.

Directives and HTML Validation

Throughout this book, we’ve used Angular’s built-in directives with the ng-directivename syntax. Examples include ng-repeat, ng-view, and ng-controller. Here, the ng portion is the namespace for Angular, and the part after the dash is the name for the directive.

While we prefer this syntax for ease of typing, it isn’t valid in many HTML validation schemes. To support these, Angular lets you invoke any directive in several ways. The following syntaxes, laid out in Table 6-1, are all equivalent to allow for your preferred validator to work properly:

Validator Format Example
none namespace-name ng-repeat=item in items
XML namespace:name ng:repeat=item in items
HTML5 data-namespace-name data-ng-repeat=item in items
xHTML x-namespace-name x-ng-repeat=item in items

Because you can use any of these, the Angular documentation lists directives with a camel-case format, instead of any of these options. For example, ng-repeat is found under the title ngRepeat. As you’ll see in a bit, you’ll use this naming format when defining your own directives.

If you don’t use an HTML validator (most folks don’t), you’ll be just fine using the namespace-directive syntax as you’ve seen in the examples so far.

API Overview

A basic pseudo-code template for creating any directive follows:

var myModule = angular.module(...);
myModule.directive('namespaceDirectiveName', function factory(injectables) {
	var directiveDefinitionObject = {
		restrict: string,
		priority: number,
		template: string,
		templateUrl: string,
		replace: bool,
		transclude: bool,
		scope: bool or object,
		controller: function controllerConstructor($scope,
		$element,
		$attrs,
		$transclude),
		require: string,
		link: function postLink(scope, iElement, iAttrs) { ... },
		compile: function compile(tElement, tAttrs, transclude) {
			return {
				pre: function preLink(scope, iElement, iAttrs, controller) { ... },
				post: function postLink(scope, iElement, iAttrs, controller) { ... }
			}
		}
	};
	return directiveDefinitionObject;
});

Some of the options are mutually exclusive, most of them are optional, and all of them have details that are worth explaining.

Table 6-2 provides an overview of when you’d use each of the options.
Table 6-2. Directive definition options
Property –> Purpose

  • restrict –> Declare how directive can be used in a template as an element, attribute, class, comment, or any combination.
  • priority –> Set the order of execution in the template relative to other directives on the element.
  • template –> Specify an inline template as a string. Not used if you’re specifying your template as a URL.
  • templateUrl –> Specify the template to be loaded by URL. This is not used if you’ve specified an inline template as a string.
  • replace –> If true, replace the current element. If false or unspecified, append this directive to the current element.
  • transclude –> Lets you move the original children of a directive to a location inside the new template.
  • scope –> Create a new scope for this directive rather than inheriting the parent scope.
  • controller –> Create a controller which publishes an API for communicating across directives.
  • require –> Require that another directive be present for this directive to function correctly.
  • link –> Programmatically modify resulting DOM element instances, add event listeners, and set up data binding.
  • compile –> Programmatically modify the DOM template for features across copies of a directive, as when used in ng-repeat.Your compile function can also return link functions to modify the resulting element instances.

Let’s dig into the details.

Naming Your Directive

You create a name for your directive with a module’s directive function, as in the following:

myModule.directive('directiveName', function factory(injectables)

Though you can name your directives anything you like, the convention is to pick a prefix namespace that identifies your directives and prevents them from colliding with external directives that you might include in your project.

You certainly wouldn’t want to name them with an ng- prefix, as that might collide with Angular’s bundled directives. If you work at SuperDuper MegaCorp, you could choose super-, superduper-, or even superduper-megacorp-, though you might choose the first option just for ease of typing.

As previously noted, Angular uses a normalized naming scheme for directives and will make camel-cased directive names available in templates in the five different validatorfriendly varieties. For example, if you’ve picked your prefix as super- and you’re writing a date-picker component, you might name it superDatePicker. In templates, you could
then use it as super-date-picker, super:date-picker, data-super-date-picker, or another variant.

The Directive Definition Object

As previously mentioned, most of the options in the directive definition are optional.In fact, there are no hard requirements and you can construct useful directives out of many subsets of the parameters. Let’s take a walk through what the options do.

restrict

The restrict property lets you specify the declaration style for your directive—that is, whether it can be used as an element name, attribute, class, or comment. You can specify one or more declaration styles using a character to represent each of them from the set in Table 6-3:
Table 6-3. Options for directive declaration usage

  • Character –> Declaration style –> Example
  • E –> element –> <my-menu title=Products></my-menu>
  • A –> attribute –> <div my-menu=Products></my-menu>
  • C –> class –> <div:Products></div>
  • M –> comment –> <!– directive: my-menu Products –>

If you wanted to use your directive as either an element or an attribute, you’d pass EA as the restrict string.

If you omit the restrict property, the default is A, and your directive can be used only as an attribute.

If you plan to support IE8, attribute- and class-based directives are your best bet, as it requires extra effort to make new elements work properly. See the Angular documentation for full details on this.

Priorities

In cases where you have multiple directives on a single DOM element and where the order in which they’re applied matters, you can use the priority property to order their application. Higher numbers run first. The default priority is 0 if you don’t specify one.

Needing to set priority will likely be a rare occurrence. One example of a directive that needs to set priority is the ng-repeat. When repeating elements, we want Angular to make copies of the template element before other directives get applied. Without this, the other directives would get applied to the canonical template element rather than to
the repeated elements we want in our app.

Though it’s not in the documentation, you can search the Angular source for the few other directives that use priority. For ng-repeat, we use a priority value of 1000, so there’s plenty of room for other priorities beneath it.

Templates

When creating components, widgets, controls, and so on, Angular lets you replace or wrap the contents of an element with a template that you provide. For example, if you were to create a set of tabbed views in your UI, you would render something like Figure 6-1.
Figure 6-1. Tabbed views

2

Instead of having a bunch of <div>, <ul><li>, and <a> elements, you could create the directives <tab-set> and <tab>, which declare the structure of each tab respectively.Your HTML then does a much better job of expressing the intent of your template. The end result could look like:

<tab-set>
<tab title='Home'>
<p>Welcome home!</p>
</tab>
<tab title='Preferences'>
<!-- preferences UI goes here -->
</tab>
</tabset>

You could also data bind the strings for title and the tab content via a controller on <tab> or <tabset>. And it’s not limited to tabs—you can do menus, accordions, pop-ups, dialog boxes, or anything else your app needs in this way.

You specify the replacement DOM elements either through the template or the templateUrl properties. You’d use template to set the template content via a string, and templateUrl to refer to the template to be loaded from a file on the server. As you’ll see in the following example, you can pre-cache these templates to reduce the number of GET requests, potentially improve performance.

Let’s write a dumb directive: a <hello> element that just replaces itself with <div>Hi there</div>. In it, we’ll set restrict to allow elements and set template to what we want to display. As the default behavior is to append content to elements, we’ll set replace to true to replace the original template:

var appModule = angular.module('app', []);
  appModule.directive('hello', function() {
    return {
      restrict: 'E',
      template: '<div>Hi there</div>',
      replace: true
    };
});

We’ll use it in a page like so:

<html lang='en' ng-app='app'>
...
<body>
<hello></hello>
</body>
...

Loading it into a browser, we see “Hi there.”

If you were to view the page source, you’d still see the <hello></hello> on the page, but if you inspected the generated source (in Chrome, right-click on Hi there and select Inspect Element), you would see:

<body>
<div>Hi there</div>
</body>

The <hello></hello> was replaced by the <div> from the template.
If you were to remove the replace: true from the directive definition, you’d see <hello><div>Hi there</div></hello>.

You’ll usually want to use templateUrl instead of template, as typing HTML into strings isn’t much fun. The template property is usually only useful for very small templates. Writing as templateUrl is useful, as these templates are cacheable by setting the appropriate headers. We could rewrite our hello directive example like so:

var appModule = angular.module('app', []);
  appModule.directive('hello', function() {
    return {
     restrict: 'E',
     templateUrl: 'helloTemplate.html',
     replace: true
    };
  });

and in helloTemplate.html, you would put:

<div>Hi there</div>

* If you are using Chrome as your browser,and you are testing with localhot ,  the “same origin policy” will prevent Chrome from loading these templates from file://, and you’ll get an error that says something like “Origin null is not allowed by Access-Control-Allow-Origin.” You have two options here:

  • Load your app through a web server
  • • Set a flag on Chrome. You can do this by running Chrome from the command line as chrome –allow-file-access-from-files

Loading these files through templateUrl will, however, make your user wait until they load to see the directive. If you want to have the template load with the first page, you can include it as part of the page in a script tag, like so:

<script type='text/ng-template' id='helloTemplateInline.html'>
  <div>Hi there</div>
</script>

The id attribute here is important, as this is the URL key that Angular uses to store the template. You’ll use this id later in your directive’s templateUrl to specify which template to insert.

This version will load just fine without a server, as no XMLHttpRequest is necessary to fetch the content.

Finally, you could load the templates yourself over $http or another mechanism and then set them directly in the object Angular uses called the $templateCache. We want this template available in the cache before the directives run, so we’ll call it via a run function on our module.

var appModule = angular.module('app', []);
appModule.run(function($templateCache) {
    $templateCache.put('helloTemplateCached.html', '<div>Hi there</div>');
});
appModule.directive('hello', function() {
   return {
     restrict: 'E',
     templateUrl: 'helloTemplateCached.html',
     replace: true
   };
});

You would likely want to do this in production only as a technique to reduce the number of GET requests required. You’d run a script to concatenate all the templates into a single file, and load it in a new module that you then reference from your main application module.

Transclusion

In addition to replacing or appending the content, you can also move the original content within the new template through the transclude property. When set to true, the directive will delete the original content, but make it available for reinsertion within your template through a directive called ng-transclude.

We could change our example to use transclusion:

appModule.directive('hello', function() {
  return {
    template: '<div>Hi there <span ng-transclude></span></div>',
    transclude: true
  };
});

applying it as:

<div hello>Bob</div>

We would see:

“Hi there Bob.”

Compile and Link Functions

While inserting templates is useful, the really interesting work of any directive happens in its compile or its link function.

The compile and link functions are named after the two phases Angular uses to create the live view for your application. Let’s take a high-level view of Angular’s initialization process, in order:

Script loads

Angular loads and looks for the ng-app directive to find the application boundaries.

Compile phase

In this phase, Angular walks the DOM to identify all the registered directives in the template. For each directive, it then transforms the DOM based on the directive’s rules (template, replace, transclude, and so on), and calls the compile function if it exists. The result is a compiled template function, which will invoke the link functions collected from all of the directives.

Link phase

To make the view dynamic, Angular then runs a link function for each directive.The link functions typically creates listeners on the DOM or the model. These listeners keep the view and the model in sync at all times.
So we’ve got the compile phase, which deals with transforming the template, and the link phase, which deals with modifying the data in the view. Along these lines, the primary difference between the compile and link functions in directives is that compile functions deal with transforming the template itself, and link functions deal with making a dynamic connection between model and view. It is in this second phase that scopes are attached to the compiled link functions, and the directive becomes live through data binding.

These two phases are separate for performance reasons. Compile functions execute only once in the compile phase, whereas link functions are executed many times, once for each instance of the directive. For example, let’s say you use ng-repeat over your directive.You don’t want to call compile, which causes a DOM-walk on each ng-repeat iteration. Instead, you want to compile once, then link.

While you should certainly learn the differences between compile and link and the capabilities of each, the majority of directives you’ll need to write will not need to transform the template; you’ll write mostly link functions.

Let’s take a look at the syntax for each of these again to compare. For compile, we have:

compile: function compile(tElement, tAttrs, transclude) {
  return {
    pre: function preLink(scope, iElement, iAttrs, controller) { ... }    ,
    post: function postLink(scope, iElement, iAttrs, controller) { ...    }
  }
}

And for link, it is:

link: function postLink(scope, iElement, iAttrs) { ... }

Notice that one difference here is that the link function gets access to a scope but compile does not. This is because during the compile phase, the scope doesn’t exist yet.You do, however, have the ability to return link functions from the compile function.These link functions do have access to the scope.

Notice also that both compile and link receive a reference to their DOM element and the list of attributes for that element. The difference here is that the compile function receives the template element and attributes from the template, and thus gets the t prefix. The link function receives them from the view instances created from the template, and thus gets the i prefix.

This distinction only matters when the directive is within some other directive that makes copies of the template. The ng-repeat directive is a good example.

<div ng-repeat='thing in things'>
  <my-widget config='thing'></my-widget>
</div>

Here, the compile function will be called exactly once, but the link function will be called once per copy of my-widget—equal to the number of elements in things. So, if my-widget needs to modify something in common to all copies (instances) of mywidget,the right place to do this, for efficiency’s sake, is in a compile function.

You will also notice that the compile function receives a transclude function as a property. Here, you have an opportunity to write a function that programmatically transcludes content for situations where the simple template-based transclusion won’t suffice.

Lastly, compile can return both a preLink and a postLink function,whereas link specifies only a postLink function. preLink, as its name implies, runs after the compile phase, but before directives on the child elements are linked. Similarly, postLink runs after all the child element directives are linked. This means that if you need to change the DOM structure, you will do so in postLink. Doing it in the preLink will confuse the attachment process and cause an error.

Scopes

You will often want to access a scope from your directive to watch model values and make UI updates when they change, and to notify Angular when external events cause the model to change. This is most common when you’re wrapping some non-Angular component from jQuery, Closure, or another library, or implementing simple DOM events. Evaluate Angular expressions passed into your directive as attributes.

When you want a scope for one of these reasons, you have three options for the type of scope you’ll get:

1. The existing scope from your directive’s DOM element.

2. A new scope you create that inherits from your enclosing controller’s scope. Here,you’ll have the ability to read all the values in the scopes above this one in the tree.This scope will be shared with any other directives on your DOM element that request this kind of scope and can be used to communicate with them.

3. An isolate scope that inherits no model properties from its parent. You’ll want to use this option when you need to isolate the operation of this directive from the parent scope when creating reusable components.
You can create these scope configurations with the following syntax:
Scope Type –> Syntax

  • existing scope –> scope: false (this is the default if unspecified)
  • new scope –> scope: true
  • isolate scope –> scope: { /* attribute names and binding style */ }

When you create an isolate scope, you don’t have access to anything in the parent scope’s model by default. You can, however, specify that you want specific attributes passed into your directive. You can think of these attribute names as parameters to the function.

Note that while isolate scopes don’t inherit model properties, they are still children of their parent scope. Like all other scopes, they have a $parent property that references their parent.

You can pass specific attributes from the parent scope to the isolate scope by passing a map of directive attribute names. There are three possible ways to pass data to and from the parent scope. We call these different ways of passing data “binding strategies.” You can also, optionally, specify a local alias for the attribute name.The syntax without aliases is in the following form:

scope: { attributeName1: 'BINDING_STRATEGY',
         attributeName2: 'BINDING_STRATEGY', …
}

With aliases, the form is:

scope: { attributeAlias: 'BINDING_STRATEGY' + 'templateAttributeName',
  …
}

The binding strategies are defined by symbols in Table 6-4:
Table 6-4. Binding strategies
Symbol –> Meaning

  • @ –> Pass this attribute as a string. You can also data bind values from enclosing scopes by using interpolation {{}} in the attribute value.
  • = –> Data bind this property with a property in your directive’s parent scope.
  • & –> Pass in a function from the parent scope to be called later.

These are fairly abstract concepts, so let’s look at some variations on a concrete example to illustrate. Let’s say that we want to create an expander directive that shows a title bar that expands to display extra content when clicked.It would look like Figure 6-2 when closed.

3

4

We would write it as follows:

<div ng-controller='SomeController'>
  <expander class='expander' expander-title='title'>
    {{text}}
  </expander>
</div>

The values for title (Click me to expand) and text (Hi there folks…), come from the enclosing scope. We could set this up with a controller like so:

function SomeController($scope) {
  $scope.title = 'Click me to expand';
  $scope.text = 'Hi there folks, I am the content
    + 'that was hidden but is now shown.';
}

We can then write this directive as:

angular.module('expanderModule', [])
  .directive('expander', function(){
    return {
      restrict: 'EA',
      replace: true,
      transclude: true,
      scope: { title:'=expanderTitle' },
      template: '<div>' +
'<div class="title" ng-click="toggle()">{{title}}</div>' +
'<div class="body" ng-show="showMe" ng-transclude></div>' +
'</div>',
      link: function(scope, element, attrs) {
        scope.showMe = false;
        scope.toggle = function toggle() {
          scope.showMe = !scope.showMe;
        }
     }
   }
});

And for styling, we’d do something like this:

.expander {
  border: 1px solid black;
  width: 250px;
}
.expander > .title {
  background-color: black;
  color: white;
  padding: .1em .3em;
  cursor: pointer;
}
.expander > .body {
  padding: .1em .3em;
}

Let’s look at what each option in the directive is doing for us, in Table 6-5.
Table 6-5. Functions of elements
Function –> Name –> Description

  • restrict: EA Invoke this directive as either an element or attribute. That is, <expander…>…</expander> and <div expander…>…</div> are equivalent.
  • replace: true Replace the original element with the template we provide.
  • transclude: true Move the original element’s content to another location in the provided template.
  • scope: { title:=expanderTitle } Create a local scope property called title that is data bound to a parent-scope property declared in the expander-title attribute. Here, we’re renaming expanderTitle as title for convenience. We could have written scope: { expanderTitle: ‘=’ } and referred to it as expanderTitle within our template instead. But in case other directives also have a title attribute,it makes sense to disambiguate our title in the API and just rename it for local use. Also notice here that the naming uses the same camel-case expansion as the directive names themselves do.
  • template: <‘div’> +… Declare the template to be inserted for this directive. Note that we’re using ng-click and ng-show to show/hide ourselves and ng-transclude to declare where the original content will go. Also note that transcluded content gets access to the parent scope, not the scope of the directive enclosing it.
  • link: … Set up the showMe model to track the expander’s open/closed state and define the toggle() function to be called when users click on the title div.

If we think it would make more sense to define the expander title in the template rather than in the model, we can use the string-style attribute passing denoted by an @ symbol in the scope declaration, like this:
scope: { title:’@expanderTitle’ },

In the template we can achieve the same effect with:

<expander class='expander' expander-title='Click me to expand'>
  {{text}}
</expander>

Note that with this @ strategy we could still data bind the title to our controller’s scope by using interpolation :

<expander class='expander' expander-title='{{title}}'>
  {{text}}
</expander>

Manipulating DOM Elements

The iElement or tElement passed to the directive’s link and compile functions are wrapped references to the native DOM element. If you have loaded the jQuery library, these are jQuery elements you’re already used to working with.

If you’re not using jQuery, the elements are inside an Angular-native wrapper called jqLite. This API has a subset of jQuery that we need to create everything in Angular.For many applications, you can do everything you need with this API alone.

If you need direct access to the raw DOM element you can get it by accessing the first element of the object with element[0].

You can see the full list of supported APIs in the Angular docs for angular.element() —the function you’d use to create jqLite-wrapped DOM elements yourself. It includes functions like addClass(), bind(), find(), toggleClass(), and so on. Again, these are all the most useful core functions from jQuery, but with a much smaller code footprint.

In addition to the jQuery APIs, elements also have Angular-specific functions. These exist whether or not you’re using the full jQuery library.

Table 6-6. Angular specific functions on an element
Function –> Description

  • controller(name) When you need to communicate directly with a controller, this function returns the controller attached to the element. If none exists for this element, it walks up the DOM and finds the nearest parent controller instead. The name parameter is optional and is used to specify the name of another directive on this same element. If provided, it will return the controller from that directive. The name should be in the camel-case format as with all directives. That is, ngModel instead of ng-model.
  • injector() Gets the injector for the current element or its parent. This allows you to ask for dependencies defined for the modules in these elements.
  • scope() Returns the scope of the current element or its nearest parent.
  • inheritedData() As with the jQuery function data(), inheritedData() sets and gets data on an element in a leak-proof way. In addition to getting data from the current element, it will also walk up the DOM to find a value.

As an example, let’s re-implement the previous expander example without the help of ng-show and ng-click. It would look like the following:

		.directive(
				'expander2',
				function() {
					return {
						restrict : 'EA',
						replace : true,
						transclude : true,
						scope : {
							title : '=expanderTitle'
						},
						template : '<div>'
								+ '<div class="title">{{title}}</div>'
								+ '<div class="body closed" ng-transclude></div>'
								+ '</div>',
						link : function(scope, element, attrs) {
							var titleElement = angular.element(element.children().eq(0));
							var bodyElement = angular.element(element.children().eq(1));
							titleElement.bind('click', toggle);
							function toggle() {
								bodyElement.toggleClass('closed');
							}
						}
					};
				});
	<div ng-controller='SomeController'>
		<expander2 class='expander' expander-title='title'> {{text}}	</expander2>
	</div>

We’ve removed the ng-click and ng-show directives from the template. Instead, to perform the desired action when users click on the expander title, we’ll create a jqLite element from the title element and bind the click event to it with a toggle() function as its callback. In toggle(), we’ll call toggleClass() on the expander body element to add or remove a class called closed, where we’d set the element to display: none with a class like this:

.closed {
  display: none;
}

Controllers

When you have nested directives that need to communicate with each other, the way to do this is through a controller. A <menu> may need to know about the <menu-item> elements inside it so it can show and hide them appropriately. The same would be true for a <tab-set> knowing about its <tab> elements, or a <grid-view> knowing about its <grid-element> elements.

As previously shown, to create an API to communicate between directives, you can declare a controller as part of a directive with the controller property syntax:

controller: function controllerConstructor($scope, $element, $attrs, $transclude)

This controller function is dependency injected, so the parameters listed here, while potentially useful, are all optional—they can be listed in any order. They’re also only a subset of the services available.

Other directives can have this controller passed to them with the require property syntax. The full form of require looks like:
require: ‘^?directiveName’.Explanations of the require string can be found in Table 6-7.

Option –> Usage

  • directiveName –> This camel-cased name specifies which directive the controller should come from. So if our <my-menuitem> directive needs to find a controller on its parent <my-menu>, we’d write it as myMenu.
  • ^ –> By default, Angular gets the controller from the named directive on the same element. Adding this optional ^ symbol says to also walk up the DOM tree to find the directive. For the <my-menu> example, we’d need to add this symbol; the final string would be \^myMenu.
  • ? –> If the required controller is not found, Angular will throw an exception to tell you about the problem. Adding a ? symbol to the string says that this controller is optional and that an exception shouldn’t be thrown if not found. Though it sounds unlikely, if we wanted to let <my-menu-item>s be used without a <mymenu> container, we could add this for a final require string of ?\^myMenu.

As an example, let’s rewrite our expander directive to be used in a set called “accordion,”which ensures that when you open one expander, the others in the set automatically close.

First, let’s write the accordion directive that will do the coordination. We’ll add our controller constructor here with methods to do the coordination:

var appModule = angular.module('app', []);
appModule.directive('accordion', function() {
	return {
		restrict : 'EA',
		replace : true,
		transclude : true,
		template : '<div ng-transclude></div>',
		controller : function() {
			var expanders = [];
			this.gotOpened = function(selectedExpander) {
				angular.forEach(expanders, function(expander) {
					if (selectedExpander != expander) {
						expander.showMe = false;
					}
				});
			};
			this.addExpander = function(expander) {
				expanders.push(expander);
			};
		}
	};
});

appModule.directive('expander', function() {
	return {
		restrict : 'EA',
		replace : true,
		transclude : true,
		require : '^?accordion',
		scope : {
			title : '=expanderTitle'
		},
		template : '<div>'
				+ '<div class="title" ng-click="toggle()">{{title}}</div>'
				+ '<div class="body" ng-show="showMe" ng-transclude></div>'
				+ '</div>',
		link : function(scope, element, attrs, accordionController) {
			scope.showMe = false;
			accordionController.addExpander(scope);
			scope.toggle = function toggle() {
				scope.showMe = !scope.showMe;
				accordionController.gotOpened(scope);
			};
		}
	};
});

with an appropriate controller, of course:

function SomeController($scope) {
	$scope.expanders = [
			{
				title : 'Click me to expand',
				text : 'Hi there folks, I am the content that was hidden but is now shown.'
			},
			{
				title : 'Click this',
				text : 'I am even better text than you have seen previously'
			},
			{
				title : 'No, click me!',
				text : 'I am text that should be seen before seeing other texts'
			} ];
}

Moving On

As we’ve seen, directives let us extend HTML’s syntax and turn many application tasks into a do-what-I-mean declaration. Directives make reuse a breeze—from configuring your app, like with ng-model and ng-controller, to doing template tasks like ngrepeat and ng-view, to sky’s-the-limit reusable components such as data-grids, bubblecharts,tool-tips, and tabs.

Angular JS Book: Chapter 4 : Analyzing an AngularJS App

We talked about some of the commonly used features of AngularJS in Chapter 2, and then dived into how your development should be structured in Chapter 3. Rather than continuing with similarly deep dives into individual features, Chapter 4 will look at a small, real-life application. We will get a feel for how all the pieces that we have been talking about (with toy examples) actually come together to form a real, working application.

Rather than putting the entire application front and center, we will introduce one portion of it at a time, then talk about the interesting and relevant parts, slowly building up to the entire application by the end of this chapter.

The Application

GutHub is a simple recipe management application, which we designed both to store our super tasty recipes and to show off various pieces of an AngularJS application. The application:
• has a two-column layout.
• has a navigation bar on the left.
• allows you to create a new recipe.
• allows you to browse the list of existing recipes.

The main view is on the right, which gets changed—depending on the URL—to either the list of recipes, the details of a single recipe, or an editable form to add to or edit existing recipes. We can see a screenshot of the application in Figure 4-1.

1

Figure 4-1. GutHub: A simple recipe management application
This entire application is available on our GitHub repo in chapter4/guthub.

Relationship Between Model, Controller, and Template

Before we dive into the application, let us spend a paragraph or two talking about how the three pieces of our application work together, and how to think about each of them.

The model is the truth. Just repeat that sentence a few times. Your entire application is driven off the model—what views are displayed, what to display in the views, what gets saved, everything! So spend some extra time thinking about your model, what the attributes of your object are going to be, and how you are going to retrieve it from the
server and save it. The view will get updated automatically through the use of data bindings, so the focus should always be on the model.

The controller holds the business logic: how you retrieve your model, what kinds of operations you perform on it, what kind of information your view needs from the model, and how you transform the model to get what you want. The responsibility of validation, making server calls, bootstrapping your view with the right data, and mostly everything
in between belongs on your controller.

Finally, the template represents how your model will be displayed, and how the user will interact with your application. It should mostly be restricted to the following:

  • Displaying your model
  • Defining the ways the user can interact with your application (clicks, input fields, and so on)
  • Styling the app, and figuring out how and when some elements are displayed (show or hide, hover, and so on)
  • Filtering and formatting your data (both input and output)

Realize that the template in Angular is not necessarily the view part of the Model View Controller design paradigm. Instead, the view is the compiled version of the template that gets executed. It is a combination of the template and the model.What should not go into the template is any kind of business logic or behavior; this information should be restricted to the controller. Keeping the template simple allows a proper separation of concerns, and also ensures that you can get the most code under test using only unit tests. Templates will have to be tested with scenario tests.

But, you might ask, where does DOM manipulation go? DOM manipulation doesn’t really go into the controllers or the template. It goes into AngularJS directives (but can sometimes be used via services, which house DOM manipulation to avoid duplication of code). We’ll cover an example of that in our GutHub example as well.

Without further ado, let’s dive right in.

The Model

We are going to keep the model dead simple for this application. There are recipes.They’re about the only model object in this entire application. Everything else builds off of it.

Each recipe has the following properties:
• An ID if it is persisted to our server
• A name
• A short description
• Cooking instructions
• Whether it is a featured recipe or not
• An array of ingredients, each with an amount, a unit, and a name
That’s it. Dead simple. Everything in the app is based around this simple model. Here’s a sample recipe for you to devour (the same one referenced in Figure 4-1):

{
    "id": "1",
    "title": "Cookies",
    "description": "Delicious, crisp on the outside, chewy on the outside, oozing with chocolatey goodness cookies. The best kind",
    "ingredients": [
        {
            "amount": "1",
            "amountUnits": "packet",
            "ingredientName": "Chips Ahoy"
        }
    ],
    "instructions": "1. Go buy a packet of Chips Ahoy\n2. Heat it up in an oven\n3. Enjoy warm cookies\n4. Learn how to bake cookies from somewhere else"
}

We will go on to see how more complicated UI features can be built around this simple model.

Controllers, Directives, and Services, Oh My!

Now we finally get to sink our teeth into the meat of this delicious application. First, we will look at the directives and services code and talk a little bit about what it is doing,then we’ll take a look at the multiple controllers needed for this application.

Services

'use strict';

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

services.factory('Recipe', ['$resource',
    function($resource) {
  return $resource('/recipes/:id', {id: '@id'});
}]);

services.factory('MultiRecipeLoader', ['Recipe', '$q',
    function(Recipe, $q) {
  return function() {
    var delay = $q.defer();
    Recipe.query(function(recipes) {
      delay.resolve(recipes);
    }, function() {
      delay.reject('Unable to fetch recipes');
    });
    return delay.promise;
  };
}]);

services.factory('RecipeLoader', ['Recipe', '$route', '$q',
    function(Recipe, $route, $q) {
  return function() {
    var delay = $q.defer();
    Recipe.get({id: $route.current.params.recipeId}, function(recipe) {
      delay.resolve(recipe);
    }, function() {
      delay.reject('Unable to fetch recipe '  + $route.current.params.recipeId);
    });
    return delay.promise;
  };
}]);

Let’s take a look at our services first. We touched upon services in “Organizing Dependencies with Modules” on page 33. Here, we’ll dig a little bit deeper.

In this file, we instantiate three AngularJS services.

There is a recipe service, which returns what we call an Angular Resource. These are RESTful resources, which point at a RESTful server. The Angular Resource encapsulates the lower level $http service, so that you can just deal with objects in your code.

With just that single line of code—return $resource—(and of course, a dependency on the guthub.services module), we can now put recipe as an argument in any of our controllers, and it will be injected into the controller. Furthermore, each recipe object has the following methods built in:

• Recipe.get()
• Recipe.save()
• Recipe.query()
• Recipe.remove()
• Recipe.delete()

*NOTA: If you are going to use Recipe.delete, and want your application to
work in IE, you will have to call it like so: Recipe[delete](). This is
because delete is a keyword in IE.

Of the previous methods, all but query work with a single recipe; query() returns an array of recipes by default.

The line of code that declares the resource—return $resource—also does a few more nice things for us:
1. Notice the :id in the URL specified for the RESTful resource. It basically says that when you make any query (say, Recipe.get()), if you pass in an object with an id field, then the value of that field will be added to the end of the URL.That is, calling Recipe.get({id: 15}) will make a call to /recipe/15.

2. What about that second object? The {id: @id}? Well, as they say, a line of code is worth a thousand explanations, so let’s take a simple example.
Say we have a recipe object, which has the necessary information already stored within it, including an id.

Then, we can save it by simply doing the following:

// Assuming existingRecipeObj has all the necessary fields,
// including id (say 13)
var recipe = new Recipe(existingRecipeObj);
recipe.$save();

This will make a POST request to /recipe/13.The @id tells it to pick the id field from its object and use that as the id parameter.It’s an added convenience that can save a few lines of code.

There are two other services in apps/scripts/services/services.js. Both of them are Loaders;one loads a single recipe (RecipeLoader), and the other loads all recipes (MultiRecipeLoader). These are used when we hook up our routes. At their cores, both of them behave very similarly. The flow of both these services is as follows:
1. Create a $q deferred object (these are AngularJS promises, used for chaining asynchronous functions).
2. Make a call to the server.
3. Resolve the deferred object when the server returns the value.
4. Return the promise that will be used by the routing mechanism of AngularJS.

*Promises in an AngularJS land

A promise is an interface that deals with objects that are returned or get filled in at a future point in time (basically, asynchronous actions). At its core, a promise is an object with a then() function.

To showcase the advantages, let us take an example where we need to fetch the current profile of a user:

var currentProfile = null;
var username = 'something';
fetchServerConfig(function(serverConfig) {
 fetchUserProfiles(serverConfig.USER_PROFILES, 
                   username,
                   function(profiles) {
                    	currentProfile = profiles.currentProfile;
                   });
});

There are a few problems with this approach:
1. The resultant code is an indentation nightmare, especially if you have to chain multiple calls.
2. Errors reported in between callbacks and functions have a tendency to be lost, unless you handle them manually at each step.
3. You have to encapsulate the logic of what you want to do with currentProfile in the innermost callback, either directly, or through a separate function.

Promises solve these issues. Before we go into the how, let’s take a look at the same problem implemented with promises:

var currentProfile =
fetchServerConfig().then(function(serverConfig) {
  return fetchUserProfiles(serverConfig.USER_PROFILES, username);
}).then(function(profiles) {
  return profiles.currentProfile;
}, function(error) {
  // Handle errors in either fetchServerConfig or
  // fetchUserProfiles here
});

Notice the advantages:
1. You can chain function calls, so you don’t get into an indentation nightmare.
2. You are assured that the previous function call is finished before the next function
in the chain is called.
3. Each then() call takes two arguments (both functions). The first one is the success
callback and the second one is the error handler.
4. In case of errors in the chain, the error will get propagated through to the rest of
the error handlers. So any error in any of the callbacks can be handled in the end.
What about resolve and reject, you ask? Well, deferred in AngularJS is a way of
creating promises. Calling resolve on it fulfills the promise (calls the success handler),
while calling reject on it calls the error handler of the promise.

We’ll come back to this again when we hook up our routes.

Directives

We can now move to the directives we will be using in our application. There will be two directives in the app:

butterbar

This directive will be shown and hidden when the routes change and while the page is still loading information. It will hook into the route-changing mechanism and automatically hide and show whatever is within its tag ,based on the state of the page.

focus

The focus directive is used to ensure that specific input fields (or elements) have the focus.

Let’s look at the code:

'use strict';

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

directives.directive('butterbar', ['$rootScope',
    function($rootScope) {
  return {
    link: function(scope, element, attrs) {
      element.addClass('hide');

      $rootScope.$on('$routeChangeStart', function() {
        element.removeClass('hide');
      });

      $rootScope.$on('$routeChangeSuccess', function() {
        element.addClass('hide');
      });
    }
  };
}]);

directives.directive('focus',
    function() {
  return {
    link: function(scope, element, attrs) {
      element[0].focus();
    }
  };
});

The preceding directive returns an object with a single property, link. We will dive deeper into how you can create your own directives in Chapter 6, but for now, all you need to know is the following:

1. Directives go through a two-step process. In the first step (the compile phase), all directives attached to a DOM element are found, and then processed. Any DOM manipulation also happens during the compile step. At the end of this phase, a linking function is produced.

2. In the second step, the link phase (the phase we used previously), the preceding DOM template produced is linked to the scope. Also, any watchers or listeners are added as needed, resulting in a live binding between the scope and the element.

Thus, anything related to the scope happens in the linking phase.
So what’s happening in our directive? Let’s take a look, shall we?
The butterbar directive can be used as follows:

<div butterbar>My loading text...</div>

It basically hides the element right up front, then adds two watches on the root scope. Every time a route change begins, it shows the element (by changing its class), and every time the route has successfully finished changing, it hides the butterbar again.

Another interesting thing to note is how we inject the $rootScope into the directive.All directives directly hook into the AngularJS dependency injection system, so you can inject your services and whatever else you need into them.

The final thing of note is the API for working with the element. jQuery veterans will be glad to know that it follows a jQuery-like syntax (addClass, removeClass). AngularJS implements a subset of the calls of jQuery so that jQuery is an optional dependency for any AngularJS project. In case you do end up using the full jQuery library in your project, you should know that AngularJS uses that instead of the jQlite implementation it has
built-in.

The second directive (focus) is much simpler. It just calls the focus() method on the current element. You can call it by adding the focus attribute on any input element, like so:

<input type="text" focus></input>

When the page loads, that element immediately gets the focus.

Controllers

With directives and services covered, we can finally get into the controllers, of which we have five. All these controllers are located in a single file (app/scripts/controllers/controllers.js), but we’ll go over them one at a time. Let’s go over the first controller,which is the List Controller, responsible for displaying the list of all recipes in the system.

app.controller('ListCtrl', ['$scope', 'recipes',
    function($scope, recipes) {
  $scope.recipes = recipes;
}]);

Notice one very important thing with the List Controller: in the constructor, it does no work of going to the server and fetching the recipes. Instead, it is handed a list of recipes already fetched. You might wonder how that’s done. We’ll answer that in the routing section of the chapter, but it has to do with the MultiRecipeLoader service we saw
previously. Just keep that in the back of your mind.

With the List Controller under our belts, the other controllers are pretty similar in nature, but we will still cover them one by one to point out the interesting aspects:

app.controller('ViewCtrl', ['$scope', '$location', 'recipe',
 function($scope, $location, recipe) {
  $scope.recipe = recipe;
  $scope.edit = function() {
   $location.path('/edit/' + recipe.id);
  };
}]);

The interesting aspect about the View Controller is the edit function it exposes on the scope. Instead of showing and hiding fields or something similar, this controller relies on AngularJS to do the heavy lifting (as should you!). The edit function simply changes the URL to the edit equivalent for the recipe, and lo and behold, AngularJS does the rest. AngularJS recognizes that the URL has changed and loads the corresponding view (which is the same recipe in edit mode). Voila!

Next, let’s take a look at the Edit Controller:

app.controller('EditCtrl', ['$scope', '$location', 'recipe',
    function($scope, $location, recipe) {
  $scope.recipe = recipe;

  $scope.save = function() {
    $scope.recipe.$save(function(recipe) {
      $location.path('/view/' + recipe.id);
    });
  };

  $scope.remove = function() {
    delete $scope.recipe;
    $location.path('/');
  };
}]);

What’s new here are the save and remove methods that the Edit Controller exposes on the scope. The save function on the scope does what you would expect it to. It saves the current recipe, and once it is done saving, redirects the user to the view screen with the same recipe. The callback function is useful in these scenarios to execute or perform some action once you are done.

There are two ways we could have saved the recipe here. One is to do it as shown in the code, by executing $scope.recipe.$save(). This is only possible because recipe is a resource object that was returned by the RecipeLoader in the first place.

Otherwise, the way you would save the recipe would be:

Recipe.save(recipe);

The remove function is also straightforward, in that it removes the recipe from the scope, and redirects users to the main landing page. Note that it doesn’t actually remove it from our server, though it shouldn’t be very hard to make that additional call.

Next, we have the New Controller:

app.controller('NewCtrl', ['$scope', '$location', 'Recipe',
    function($scope, $location, Recipe) {
  $scope.recipe = new Recipe({
    ingredients: [ {} ]
  });

  $scope.save = function() {
    $scope.recipe.$save(function(recipe) {
      $location.path('/view/' + recipe.id);
    });
  };
}]);

The New Controller is almost exactly the same as the Edit Controller. In fact, you could look at combining the two into a single controller as an exercise. The only major difference is that the New Controller creates a new recipe (which is a resource, so that it has the save function) as the first step. Everything else remains unchanged.

Finally, we have the Ingredients Controller. This is a special controller, but before we get into why or how, let’s take a look:

app.controller('IngredientsCtrl', ['$scope',
    function($scope) {
  $scope.addIngredient = function() {
    var ingredients = $scope.recipe.ingredients;
    ingredients[ingredients.length] = {};
  };
  $scope.removeIngredient = function(index) {
    $scope.recipe.ingredients.splice(index, 1);
  };
}]);

All the other controllers that we saw so far are linked to particular views on the UI. But the Ingredients Controller is special. It’s a child controller that is used on the edit pages to encapsulate certain functionality that is not needed at the higher level. The interesting thing to note is that since it is a child controller, it inherits the scope from the parent controller (the Edit/New controllers in this case). Thus, it has access to the $scope.recipe from the parent.

The controller itself does nothing too interesting or unique. It just adds a new ingredient to the array of ingredients present on the recipe, or removes a specific ingredient from the list of ingredients on the recipe.

With that, we finish the last of the controllers. The only JavaScript piece that remains is how the routing is set up:

var app = angular.module('guthub',
    ['guthub.directives', 'guthub.services']);

app.config(['$routeProvider', function($routeProvider) {
    $routeProvider.
      when('/', {
        controller: 'ListCtrl',
        resolve: {
          recipes: ["MultiRecipeLoader", function(MultiRecipeLoader) {
            return MultiRecipeLoader();
          }]
        },
        templateUrl:'/guthub/app/views/list.html'
      }).when('/edit/:recipeId', {
        controller: 'EditCtrl',
        resolve: {
          recipe: ["RecipeLoader", function(RecipeLoader) {
            return RecipeLoader();
          }]
        },
        templateUrl:'/guthub/app/views/recipeForm.html'
      }).when('/view/:recipeId', {
        controller: 'ViewCtrl',
        resolve: {
          recipe: ["RecipeLoader", function(RecipeLoader) {
            return RecipeLoader();
          }]
        },
        templateUrl:'/guthub/app/views/viewRecipe.html'
      }).when('/new', {
        controller: 'NewCtrl',
        templateUrl:'/guthub/app/views/recipeForm.html'
      }).otherwise({redirectTo:'/'});
}]);

As promised, we finally reached the point where the resolve functions are used. The previous piece of code sets up the Guthub AngularJS module, as well as the routes and templates involved in the application.

It hooks up the directives and the services that we created, and then specifies the various routes we will have in our application.

For each route, we specify the URL, the controller that backs it up, the template to load,and finally (optionally), a resolve object.

This resolve object tells AngularJS that each of these resolve keys needs to be satisfied before the route can be displayed to the user. For us, we want to load all the recipes, or an individual recipe, and make sure we have the server response before we display the page. So we tell the route provider that we have recipes (or a recipe), and then tell it how
to fetch it.

This links back to the two services we defined in the first section, the MultiRecipeLoad er and the RecipeLoader. If the resolve function returns an AngularJS promise, then AngularJS is smart enough to wait for the promise to get resolved before it proceeds.That means that it will wait until the server responds.

The results are then passed into the constructor as arguments (with the names of the parameters being the object’s fields).

Finally, the otherwise function denotes the default URL redirect that needs to happen when no routes are matched.

You might notice that both the Edit and the New controller routes lead
to the same template URL, views/recipeForm.html. What’s happening
here? We reused the edit template. Depending on which controller is
associated, different elements are shown in the edit recipe template.
With this done, we can now move on to the templates, how these controllers hook up to them, and manage what is shown to the end user.

The Templates

Let us start by taking a look at the outermost, main template, which is the index.html.This is the base of our single-page application, and all the other views are loaded within the context of this template:

<!DOCTYPE html>
<html   lang="en" ng-app="guthub">
<head>
  <title>GutHub - Create and Share</title>
  <script src="scripts/vendor/angular.min.js"></script>
  <script src="scripts/vendor/angular-resource.min.js"></script>
  <script src="scripts/directives/directives.js"></script>
  <script src="scripts/services/services.js"></script>
  <script src="scripts/controllers/controllers.js"></script>
  <link href="styles/bootstrap.css" rel="stylesheet">
  <link href="styles/guthub.css" rel="stylesheet">
</head>
<body>
  <header>
    <h1>GutHub</h1>
  </header>

  <div butterbar>Loading...</div>

  <div class="container-fluid">
    <div class="row-fluid">
      <div class="span2">
        <!--Sidebar-->
        <div id="focus"><a href="/#/new">New Recipe</a></div>
        <div><a href="/#/">Recipe List</a></div>

      </div>
      <div class="span10">
        <div ng-view></div>
      </div>
    </div>
  </div>
</body>
</html>

There are five interesting elements to note in the preceding template, most of which you already encountered in Chapter 2. Let’s go over them one by one:

ng-app

We set the ng-app module to be GutHub. This is the same module name we gave in our angular.module function. This is how AngularJS knows to hook the two together.

script tag

This is where AngularJS is loaded for the application. It has to be done before all your JS files that use AngularJS are loaded. Ideally, this should be done at the bottom of the body.

Butterbar

Aha! Our first usage of a custom directive. When we defined our butterbar directive before, we wanted to use it on an element so that it would be shown when the routes were changing, and hidden on success. The highlighted element’s text is shown (a very boring “Loading…” in this case) as needed.

Link href Values

The hrefs link to the various pages of our single-page application. Notice how they use the # character to ensure that the page doesn’t reload, and are relative to the current page. AngularJS watches the URL (as long as the page isn’t reloaded), and works it magic (or actually, the very boring route management we defined as part of our routes) when needed.

ng-view

This is where the last piece of magic happens. In our controllers section, we defined our routes. As part of that definition, we denoted the URL for each route, the controller associated with the route, and a template. When AngularJS detects a route change, it loads the template, attaches the controller to it, and replaces the ngview with the contents of the template.

One thing that is conspicuous in its absence is the ng-controller tag. Most applications would have some sort of a MainController associated with the outer template. Its most common location would be on the body tag. In this case, we didn’t use it, because the entire outer template has no AngularJS content that needs to refer to a scope.

Now let’s look at the individual templates associated with each controller, starting with the “list of recipes” template:

 chapter4/guthub/app/views/list.html 

<h3>Recipe List</h3>
<ul class="recipes">
  <li ng-repeat="recipe in recipes">
    <div><a ng-href="/#/view/{{recipe.id}}">{{recipe.title}}</a></div>
  </li>
</ul>

Really, it’s a very boring template. There are only two points of interest here. The first one is a very standard usage of the ng-repeat tag. It picks up all the recipes from the scope, and repeats over them.

The second is the usage of the ng-href tag instead of href. This is purely to avoid having a bad link during the time that AngularJS is loading up. The ng-href ensures that at no time is a malformed link presented to the user. Always use this whenever your URLs are dynamic instead of static.

Of course you might wonder: where is the controller? There is no ng-controller defined, and there really was no Main Controller defined. This is where route mapping comes into play. If you remember (or peek back a few pages), the / route redirected to the list template and had the List Controller associated with it. Thus, when any references are made to variables and the like, it is within the scope of the List Controller.

Now we move on to something with a little bit more meat: the view form.

<h2>{{recipe.title}}</h2>

<div>{{recipe.description}}</div>

<h3>Ingredients</h3>
<span ng-show="recipe.ingredients.length == 0">No Ingredients</span>
<ul class="unstyled" ng-hide="recipe.ingredients.length == 0">
  <li ng-repeat="ingredient in recipe.ingredients">
    <span>{{ingredient.amount}}</span>
    <span>{{ingredient.amountUnits}}</span>
    <span>{{ingredient.ingredientName}}</span>
  </li>
</ul>

<h3>Instructions</h3>
<div>{{recipe.instructions}}</div>

<form ng-submit="edit()" class="form-horizontal">
  <div class="form-actions">
    <button class="btn btn-primary">Edit</button>
  </div>
</form>

Another nice, small, contained template. We’ll draw your attention to three things, though not necessarily in the order they are shown!

The first is the pretty standard ng-repeat. The recipes are again in the scope of the View Controller, which is loaded by the resolve function before this page is displayed to the user. This ensures that the page is not in a broken, unloaded state when the user sees it.

The next interesting usage is that of ng-show and ng-class to style the template. The ng-show tag has been added to the <i> tag, which is used to display a starred icon. Now, the starred icon is shown only when the recipe is a featured recipe (as denoted by the recipe.featured boolean value). Ideally, to ensure proper spacing, you would have another empty spacer icon, with an ng-hide directive on it, with the exact same AngularJS
expression as shown in the ng-show. That is a very common usage, to display one thing and hide another on a given condition.The ng-class is used to add a class to the <h2> tag (“featured” in this case) when the
recipe is a featured recipe. That adds some special highlighting to make the title stand out even more.

The final thing to note is the ng-submit directive on the form. The directive states that the edit() function on the scope is called in case the form is submitted. The form submission happens when any button without an explicit function attached (in this case, the Edit button) is clicked. Again, AngularJS is smart enough to figure out the scope
that is being referred to (from the module, the route, and the controller) and call the right method at the right time.

Now we can move on to our final template (and possibly the most complicated one yet),the recipe form template.

<h2>Edit Recipe</h2>
<form name="recipeForm" ng-submit="save()" class="form-horizontal">
  <div class="control-group">
    <label class="control-label" for="title">Title:</label>
    <div class="controls">
      <input ng-model="recipe.title" class="input-xlarge" id="title" focus required>
    </div>
  </div>

  <div class="control-group">
    <label class="control-label" for="description">Description:</label>
    <div class="controls">
      <textarea ng-model="recipe.description" class="input-xlarge" id="description"></textarea>
    </div>
  </div>

  <div class="control-group">
    <label class="control-label" for="ingredients">Ingredients:</label>
    <div class="controls">
      <ul id="ingredients" class="unstyled" ng-controller="IngredientsCtrl">
        <li ng-repeat="ingredient in recipe.ingredients">
          <input ng-model="ingredient.amount" class="input-mini">
          <input ng-model="ingredient.amountUnits" class="input-small">
          <input ng-model="ingredient.ingredientName">
          <button type="button" class="btn btn-mini" ng-click="removeIngredient($index)"><i class="icon-minus-sign"></i> Delete </button>
        </li>
        <button type="button" class="btn btn-mini" ng-click="addIngredient()"><i class="icon-plus-sign"></i> Add </button>
      </ul>
    </div>
  </div>

  <div class="control-group">
    <label class="control-label" for="instructions">Instructions:</label>
    <div class="controls">
      <textarea ng-model="recipe.instructions" class="input-xxlarge" id="instructions"></textarea>
    </div>
  </div>

  <div class="form-actions">
    <button class="btn btn-primary" ng-disabled="recipeForm.$invalid">Save</button>
    <button type="button" ng-click="remove()" ng-show="!recipe.id" class="btn">Delete</button>
  </div>
</form>

Don’t panic. It looks like a lot of code, and it is a lot of code, but if you actually dig into it, it’s not very complicated. In fact, a lot of it is simple, repetitive boilerplate to show editable input fields for editing recipes:

• The focus directive is added on the very first input field (the title input field).This ensures that when the user navigates to this page, the title field has focus so the user can immediately start typing in the title.

• The ng-submit directive is used very similarly to the previous example, so we won’t dive into it much, other than to say that it saves the state of the recipe and signals the end of the editing process. It hooks up to the save() function in the Edit Controller.

• The ng-model directive is used to bind the various input boxes and text areas on the field to the model.

• One of the more interesting aspects on this page, and one we recommend you spend some time trying to understand, is the ng-controller tag on the ingredients list portion. Let’s take a minute to understand what is happening here.

We see a list of ingredients being displayed, and the container tag is associated with an ng-controller. That means that the whole <ul> tag is scoped to the Ingredients Controller. But what about the actual controller of this template, the Edit Controller?

As it turns out, the Ingredients Controller is created as a child controller of the Edit Controller, thereby inheriting the scope of Edit Controller. That is why it has access to the recipe object from the Edit Controller.

In addition, it adds the addIngredient() method, which is used by the highlighted ng-click, which is accessible only within the scope of the <ul> tag. Why would you want to do this? This is the best way to separate your concerns. Why should the Edit Controller have an addIngredients() method, when 99% of the template doesn’t care about it? Child and nested controllers are awesome for such precise, contained tasks, and allow you to separate your business logic into more manageable
chunks.

• The other directive that we want to cover in some depth here is the form validation controls. It is easy enough in the AngularJS world to set a particular form field “as required.” Simply add the required tag to the input (as is the case in the preceding code). But now what do you do with it?
For that, we jump down to the Save button. Notice the ng-disabled directive on it, which says recipeForm.$invalid. The recipeForm is the name of the form which we have declared. AngularJS adds some special variables to it ($valid and $invalid being just two) that allow you to control the form elements. AngularJS looks at all the required elements and updates these special variables accordingly.So if our Recipe Title is empty, recipeForm.$invalid gets set to true (and $val id to false), and our Save button is instantly disabled.

We can also set the max and min length of an input, as well as a Regex pattern against which an input field will be validated. Furthermore, there are advanced usages that can be applied to show certain error messages only when specific conditions are met. Let us diverge for a bit with a small example:

<form name="myForm">
User name: <input type="text"
name="userName"
ng-model="user.name"
ng-minlength="3">
<span class="error"
ng-show="myForm.userName.$error.minlength">Too Short!</span>
</form>

In the preceding example, we add a requirement that the username be at least three characters (through the use of the ng-minlength directive). Now, the form gets populated with each named input in its scope—we have only userName in this example— each of which will have an $error object (which will further include what kind of error it has or doesn’t have: required, minlength, maxlength, or pattern) and a $valid tag to signal whether the input itself is valid or not.

We can use this to selectively show error messages to the user, depending on the type of input error he is making, as we do in the previous example.

Jumping back to our original template—Recipe form template—there is another nice usage of the ng-show highlighted within the ingredients repeater scope. The Add Ingredient button is shown only beside the last ingredient. This is accomplished by calling an ng-show and using the special $last variable that is accessible inside a repeater element scope.

Finally, we have the last ng-click, which is attached to the second button, used for deleting the recipe. Notice how the button only shows if the recipe is not saved yet. While usually it would make more sense to write ng-hide=”recipe.id”, sometimes it makes more semantic sense to say ng-show=”!recipe.id”. That is, show if the recipe doesn’t have an id, rather than hide if the recipe has an id.

The Tests

We have been holding off on showing you the tests that go along with the controller, but you knew they were coming, didn’t you? In this section, we’ll go over what kinds of  tests you would write for which parts of the code, and how you would actually write them.

Unit Tests

The first and most important kind of test is the unit test. This tests that the controllers (and directives, and services) that you have developed are correctly structured and written, and that they do what you would expect them to.

Before we dive into the individual unit tests, let us take a look at the test harness that surrounds all of our controller unit tests:

describe('Controllers', function() {
	var $scope, ctrl;
	//you need to indicate your module in a test
	beforeEach(module('guthub'));
	beforeEach(function() {
		this.addMatchers({
		toEqualData: function(expected) {
			return angular.equals(this.actual, expected);
		}
	});
});

describe('ListCtrl', function() {....});
	// Other controller describes here as well
});

The harness (we are still using Jasmine to write these tests in a behavioral manner) does a few things:
1. Creates a globally (at least for the purpose of this test spec) accessible scope and controller, so we don’t worry about creating a new variable for each controller.
2. Initializes the module that our app uses (GutHub in this case).
3. Adds a special matcher that we call equalData. This basically allows us to perform assertions on resource objects (like recipes) that are returned through the $resource service or RESTful calls.

* Remember to add the special matcher called equalData any time we
want to do assertions on ngResource returned objects. This is because
ngResource returned objects have additional methods on them that will
fail normal expect equal calls.

With that harness in place, let’s take a look at the unit tests for the List Controller:

  describe('ListCtrl', function() {
    var mockBackend, recipe;
    // The _$httpBackend_ is the same as $httpBackend. Only written this way to
    // differentiate between injected variables and local variables
    beforeEach(inject(function($rootScope, $controller, _$httpBackend_, Recipe) {
      recipe = Recipe;
      mockBackend = _$httpBackend_;
      $scope = $rootScope.$new();
      ctrl = $controller('ListCtrl', {
        $scope: $scope,
        recipes: [1, 2, 3]
      });
    }));

    it('should have list of recipes', function() {
      expect($scope.recipes).toEqual([1, 2, 3]);
    });
  });

Remember that the List Controller is one of the simplest controllers we have. The constructor of the controller just takes in a list of recipes and saves it to the scope. You could write a test for it, but it seems kind of silly (we still did it, because tests are awesome!).

Instead, the more interesting aspect is the MultiRecipeLoader service. This is responsible for fetching the list of recipes from the server and passing it in as an argument (when hooked up correctly via the $route service):

  describe('MultiRecipeLoader', function() {
    var mockBackend, recipe, loader;
    // The _$httpBackend_ is the same as $httpBackend. Only written this way to
    // differentiate between injected variables and local variables
    beforeEach(inject(function(_$httpBackend_, Recipe, MultiRecipeLoader) {
      recipe = Recipe;
      mockBackend = _$httpBackend_;
      loader = MultiRecipeLoader;
    }));

    it('should load list of recipes', function() {
      mockBackend.expectGET('/recipes').respond([{id: 1}, {id: 2}]);

      var recipes;

      var promise = loader();
      promise.then(function(rec) {
        recipes = rec;
      });

      expect(recipes).toBeUndefined();

      mockBackend.flush();

      expect(recipes).toEqualData([{id: 1}, {id: 2}]);
    });
  });

We test the MultiRecipeLoader by hooking up a mock HttpBackend in our test. This comes from the angular-mocks.js file that is included when these tests are run. Just injecting it into your beforeEach method is enough for you to start setting expectations on it.

In our second, more meaningful test, we set an expectation for a server GET call to recipes, which will return a simple array of objects. We then use our new custom matcher to ensure that this is exactly what was returned. Note the call to flush() on the mock backend, which tells the mock backend to now return response from the server. You can use this mechanism to test control flow and see how your application handles before and after the server returns a response.

We will skip View Controller, as it is almost exactly like the List Controller except for the addition of an edit() method on the scope. This is pretty simple to test, as you can inject the $location into your test and check its value.

Let us now jump to the Edit Controller, which has two points of interest that we should be unit testing. The resolve function is similar to the one we saw before, and can be tested the same way. Instead, we now want to see how we can test the save() and the remove() methods. Let’s take a look at the tests for those (assuming our harnesses from the previous example):

  describe('EditController', function() {
    var mockBackend, location;
    beforeEach(inject(function($rootScope, $controller, _$httpBackend_, $location, Recipe) {
      mockBackend = _$httpBackend_;
      location = $location;
      $scope = $rootScope.$new();

      ctrl = $controller('EditCtrl', {
        $scope: $scope,
        $location: $location,
        recipe: new Recipe({id: 1, title: 'Recipe'})
      });
    }));

    it('should save the recipe', function() {
      mockBackend.expectPOST('/recipes/1', {id: 1, title: 'Recipe'}).respond({id: 2});

      // Set it to something else to ensure it is changed during the test
      location.path('test');

      $scope.save();
      expect(location.path()).toEqual('/test');

      mockBackend.flush();

      expect(location.path()).toEqual('/view/2');
    });

    it('should remove the recipe', function() {
      expect($scope.recipe).toBeTruthy();
      location.path('test');

      $scope.remove();

      expect($scope.recipe).toBeUndefined();
      expect(location.path()).toEqual('/');
    });
  });

In the first test, we test the save() function. In particular, we ensure that saving first makes a POST request to the server with our object, and then, once the server responds, the location is changed to the newly persisted object’s view recipe page.

The second test is even simpler. We simply check to ensure that calling remove() on the scope removes the current recipe, then redirects the user to the main landing page. This can be easily done by injecting the $location service into our test, and working with it.

The rest of the unit tests for the controllers follow very similar patterns, so we can skip over them. At their base, such unit tests rely on a few things:
• Ensuring that the controller (or more likely, the scope) reaches the correct state at the end of the initialization
• Confirming that the correct server calls are made, and that the right state is achieved by the scope during the server call and after it is completed (by using our mocked out backend in the unit tests)
• Leveraging the AngularJS dependency injection framework to get a handle on the elements and objects that the controller works with to ensure that the controller is getting set to the correct state

Scenario Tests

Once we are happy with our unit tests, we might be tempted to just lean back, smoke a cigar, and call it a day. But the work of an AngularJS developer isn’t done until he has run his scenario tests. While unit tests assure us that every small piece of JS code is working as intended, we also want to ensure that the template loads, that it is hooked up correctly to the controllers, and that clicking around in the template does the right
thing.

This is exactly what a scenario test in AngularJS does for you. It allows you to:
• Load your application
• Browse to a certain page
• Click around and enter text willy-nilly
• Ensure that the right things happen

So how would a scenario test for our “list of recipes” page work? Well, first of all, before we get started on the actual test, we need to do some groundwork.

For the scenario test to work, we will need a working web server that is ready to accept requests from the GutHub application, and will allow storing and getting a list of recipes from it. Feel free to change the code to use an in-memory list of recipes (removing the recipe $resource and changing it to just a JSON object dump), or to reuse and modify the web server we showed you in the previous chapter, or to use Yeoman!

Once we have a server up and running, and serving our application, we can then write and run the following test:

describe('GutHub App', function() {
  it('should show a list of recipes', function() {
    browser().navigateTo('/#/');
    // Our Default GutHub recipes list has two recipes
    expect(repeater('.recipes li').count()).toEqual(2);
  });
});

 

HTML5 Canvas

Welcome to Basic Tutorials! In these tutorials we’ll focus on the fundamental drawing capabilities of the HTML5 Canvas, including line and curve drawing, path drawing, shape drawing, gradients, patterns, images, and text.

HTML5 Canvas Basic Tutorials Prerequisites

All you need to get started with Basic Tutorials is a modern browser such as Google Chrome, Firefox, Safari, Opera, or IE9, a good working knowledge of JavaScript, and a simple text editor like notepad

The HTML5 Canvas element is an HTML tag similar to the <div>, <a>, or <table> tag, with the exception that its contents are rendered with JavaScript. In order to leverage the HTML5 Canvas, we’ll need to place the canvas tag somewhere inside the HTML document, access the canvas tag with JavaScript, create a context, and then utilize the HTML5 Canvas API to draw visualizations.

When using canvas, it’s important to understand the difference between the canvas element and the canvas context, as often times people get these confused. The canvas element is the actual DOM node that’s embedded in the HTML page. The canvas context is an object with properties and methods that you can use to render graphics inside the canvas element. The context can be 2d or webgl (3d).

Each canvas element can only have one context. If we use the getContext() method multiple times, it will return a reference to the same context object.

HTML5 Canvas Template

<body>
  <canvas id="myCanvas" width="578" height="200"></canvas>
  <script>
    var canvas = document.getElementById('myCanvas');
    var context = canvas.getContext('2d');

    // do stuff here
  </script>
</body>

To draw a line using HTML5 Canvas, we can use the beginPath(), moveTo(), lineTo(), and stroke() methods. First, we can use the beginPath() method to declare that we are about to draw a new path. Next, we can use the moveTo() method to position the context point (i.e. drawing cursor), and then use the lineTo() method to draw a straight line from the starting position to a new position. Finally, to make the line visible, we can apply a stroke to the line using stroke(). Unless otherwise specified, the stroke color is defaulted to black.

<!DOCTYPE HTML>
<html>
  <head>
    <style>
      body {
        margin: 0px;
        padding: 0px;
      }
    </style>
  </head>
  <body>
    <canvas id="myCanvas" width="578" height="200"></canvas>
    <script>
      var canvas = document.getElementById('myCanvas');
      var context = canvas.getContext('2d');

      context.beginPath();
      context.moveTo(100, 150);
      context.lineTo(450, 50);
      context.stroke();
    </script>
  </body>
</html>

To draw an image using HTML5 Canvas, we can use the drawImage() method which requires an image object and a destination point. The destination point defines the top left corner of the image relative to the top left corner of the canvas. Since the drawImage() method requires an image object, we must first create an image and wait for it to load before instantiating drawImage(). We can accomplish this by using the onload property of the image object.

<!DOCTYPE HTML>
<html>
  <head>
    <style>
      body {
        margin: 0px;
        padding: 0px;
      }
    </style>
  </head>
  <body>
    <canvas id="myCanvas" width="578" height="400"></canvas>
    <script>
      var canvas = document.getElementById('myCanvas');
      var context = canvas.getContext('2d');
      var imageObj = new Image();

      imageObj.onload = function() {
        context.drawImage(imageObj, 69, 50);
      };
      imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
    </script>
  </body>
</html>

Data URI scheme

[Fuente:             http://en.wikipedia.org/wiki/Data_URI_scheme]

El esquema data URI es un URI scheme (Uniform Resource Identifier scheme) que proporciona una forma de incluir datos in-line en páginas web como si fueran recursos externos. Esta técnica te permite por ejemplo descargar en una sola petición HTTP imágenes y hojas de estilos antes que hacer múltiples peticiones HTTP lo cual puede ser ineficiente.

Los data URIs tienden a ser más simples que métodos de inclusión, tales como MIME with cid or mid URIs. Los data URIs se les llama algunas veces URL (Uniform Resource Locators) , aunque no referencien nada remoto. El esquema data URI está definido en RFC 2397 of the Internet Engineering Task Force (IETF).

En los browsers que soportan completamente Data URIs para “navigation”, contenido generado por Javascript se le puede provocar como si fuera una descarga de fichero para el usuario, simplemente asignando el Data Uri al window.location.href. Como ejemplo valga la conversión de tablas HTML a CSV para descargar utilizando Data un URI como este:

data:text/csv;charset=UTF-8,' + encodeURIComponent(csv)

donde “csv” ha sido generado por Javascript.

La IETF publicó la especificación data URI en 1998 y no ha cambiado desde entonces. La especificación HTML 4.01 se refiere al data URI scheme y este esquema ha sido implementado en la mayoría de los navegadores.

Web browser support

As of March 2012, Data URIs are supported by the following web browsers:

  • Gecko-based, such as FirefoxSeaMonkeyXeroBankCaminoFennec and K-Meleon
  • Konqueror, via KDE‘s KIO slaves input/output system
  • Opera (including devices such as the Nintendo DSi or Wii)
  • WebKit-based, such as Safari (including iOS), Android‘s browser, Kindle 4’s browser, Epiphany and Midori (WebKit is a derivative of Konqueror’s KHTML engine, but Mac OS X does not share the KIO architecture so the implementations are different), and Webkit/Chromium-based, such as Chrome
  • Trident
    • Internet Explorer 8: Microsoft has limited its support to certain “non-navigable” content for security reasons, including concerns that JavaScript embedded in a data URI may not be interpretable by script filters such as those used by web-based email clients. Data URIs must be smaller than 32 KB in Version 8.[3] Data URIs are supported only for the following elements and/or attributes:[4]
      • object (images only)
      • img
      • input type=image
      • link
      • CSS declarations that accept a URL, such as background-imagebackgroundlist-style-typelist-style and similar.
    • Internet Explorer 9: Internet Explorer 9 does not have 32KB limitation and supports more elements.

Email Client support

Following clients support data URI for images[3]

Format

data:[<MIME-type>][;charset=<encoding>][;base64],<data>

The encoding is indicated by ;base64. If it’s present the data is encoded as base64. Without it the data (as a sequence of octets) is represented using ASCII encoding for octets inside the range of safe URL characters and using the standard %xx hex encoding of URLs for octets outside that range. If <MIME-type> is omitted, it defaults to text/plain;charset=US-ASCII. (As a shorthand, the type can be omitted but the charset parameter supplied.)

Some browsers (Chrome, Opera, Safari, Firefox) accept a non-standard ordering if both ;base64 and ;charset are supplied, while Internet Explorer requires that the charset’s specification must precede the base64 token.

Advantages and disadvantages

Advantages

  • HTTP request and header traffic is not required for embedded data, so data URIs consume less bandwidth whenever the overhead of encoding the inline content as a data URI is smaller than the HTTP overhead. For example, the required base64 encoding for an image 600 bytes long would be 800 bytes, so if an HTTP request required more than 200 bytes of overhead, the data URI would be more efficient.
  • For transferring many small files (less than a few kilobytes each), this can be fasterTCP transfers tend to start slowly. If each file requires a new TCP connection, the transfer speed is limited by the round-trip time rather than the available bandwidth. Using HTTP keep-alive improves the situation, but may not entirely alleviate the bottleneck.
  • While web browsers will not cache inline-loaded data as separate resource, external CSS files using data URIs are cached, so that an external CSS file with 10 background-images embedded as data URIs requires only one initial request instead of eleven and subsequent requests require only retrieving one cached CSS file, instead of one CSS file plus ten cached images.
  • When browsing a secure HTTPS web site, web browsers commonly require that all elements of a web page be downloaded over secure connections, or the user will be notified of reduced security due to a mixture of secure and insecure elements. On badly configured servers, HTTPS requests have significant overhead over common HTTP requests, so embedding data in data URIs may improve speed in this case.
  • Web browsers are usually configured to make only a certain number of (often two) concurrent HTTP connections to a domain,[5] so inline data frees up a download connection for other content.
  • Environments with limited or restricted access to external resources may embed content when it is disallowed or impractical to reference it externally. For example, an advanced HTML editing field could accept a pasted or inserted image and convert it to a data URI to hide the complexity of external resources from the user. Alternatively, a browser can convert (encode) image based data from the clipboard to a data URI and paste it in a HTML editing field. Mozilla Firefox 4 supports this functionality.
  • It is possible to manage a multimedia page as a single file.
  • Email message templates can contain images (for backgrounds or signatures) without the image appearing to be an “attachment”.

Disadvantages[edit]

  • Data URIs are not separately cached from their containing documents (e.g. CSS or HTML files), therefore the encoded data is downloaded every time the containing documents are re-downloaded.
  • Content must be re-encoded and re-embedded every time a change is made.
  • Internet Explorer through version 7 (approximately 5% of web traffic as of September 2011), lacks support. However this can be overcome by serving browser-specific content.[6]
  • Internet Explorer 8 limits data URIs to a maximum length of 32 KB. (Internet Explorer 9 does not have this limitation)[3][4]
  • In IE 8 and 9, data URIs can only be used for images, but not for navigation or JavaScript generated file downloads.[7]
  • Data URIs are included as a simple stream, and many processing environments (such as web browsers) may not support using containers (such as multipart/alternative or message/rfc822) to provide greater complexity such as metadatadata compression, or content negotiation.
  • Base64-encoded data URIs are 1/3 times larger in size than their binary equivalent. (However, this overhead is reduced to 2–3% if the HTTP server compresses the response using gzip)[8]
  • Data URIs do not carry a file name as a normal linked file would. When saving, a default file name for the specified MIME type is generally used.
  • Referencing the same resource (such as an embedded small image) more than once from the same document results in multiple copies of the embedded resource. In comparison, an external resource can be referenced arbitrarily many times, yet downloaded and decoded only once.
  • Data URIs make it more difficult for security software to filter content.[9]

Examples

HTML

An HTML fragment embedding a picture of small red dot: Red-dot-5px.png

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA
AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot" />

As demonstrated above, data URIs encoded with base64 may contain whitespace for readability.

CSS

A CSS rule that includes a background image:

ul.checklist li.complete {
    padding-left: 20px;
    background: white url('data:image/png;base64,iVBORw0KGgoAA
AANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD///+l2Z/dAAAAM0l
EQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4Ug9C9zwz3gVLMDA/A6
P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC') no-repeat scroll left top;
}

In Mozilla Firefox 5Google Chrome 17, and IE 9 (released June, 2011), encoded data must not contain newlines.

JavaScript

JavaScript statement that opens an embedded subwindow, as for a footnote link:

window.open('data:text/html;charset=utf-8,' + 
    encodeURIComponent( // Escape for URL formatting
        '<!DOCTYPE html>'+
        '<html lang="en">'+
        '<head><title>Embedded Window</title></head>'+
        '<body><h1>42</h1></body>'+
        '</html>'
    )
);

This example does not work with Internet Explorer 8 due to its security restrictions that prevent navigable file types from being used.[4]