Author Archives: admin

JSONP: JSON con padding

[Fuente: http://es.wikipedia.org/wiki/JSONP]

JSONP o “JSON con padding” es una técnica de comunicación utilizada en los programas JavaScript para realizar llamadas asíncronas a dominios diferentes. JSONP es un método concebido para suplir la limitación de AJAX entre dominios, que únicamente permite realizar peticiones a páginas que se encuentran bajo el mismo dominio y puerto por razones de seguridad.

Razón del JSONP

Bajo la política del mismo origen (SOP), un código JavaScript cargado en un dominio no tiene permiso para obtener datos de otro dominio. Sin embargo, esta restricción no se aplica a la etiqueta <script> de HTML, para la cual se puede especificar en su atributo src la URL de un script alojado en un servidor remoto.

Cómo funciona

Para realizar llamadas asíncronas entre distintos dominios, los datos se obtienen cargando un script que contiene el objeto JSON.

<script type="text/javascript" src="http://servidor.ejemplo.com/datos.json"></script>

De por sí, esto provocaría un error de sintaxis ya que el navegador estaría tratando de interpretar JSON crudo como JavaScript. Y aún suponiendo que el navegador interpretase el objeto JSON como un objeto literal de JavaScript, sin estar asignado a una variable no sería accesible.

{
    "api_key": "224Wrf2asfSDfcea23reSDfqW",
    "status": "good",
    "name": "wikipedia",
    "date": "27-09-1995"
}

En la técnica de JSONP, el objeto JSON se devuelve envuelto en la llamada de una función. De esta forma, una función ya definida en el entorno de JavaScript podría manipular los datos JSON.

jsonCallback ({
    "api_key": "224Wrf2asfSDfcea23reSDfqW",
    "status": "good",
    "name": "wikipedia",
    "date": "27-09-1995"
});

Por convención, el nombre de la función de retorno se especifica mediante un parámetro de la consulta, normalmente, utilizando jsonp o callback como nombre del campo en la solicitud al servidor.

<script type="text/javascript" src="http://servidor.ejemplo.com/datos.json?callback=parseJSON"></script>

Padding

Aunque el padding es generalmente el nombre de la función que envuelve al objeto JSON, también es posible asignar el objeto a una variable o realizar cualquier otra sentencia o declaración de JavaScript. La petición JSONP no es JSON crudo y no es analizada como tal, por lo que se puede devolver cualquier expresión válida de JavaScript, y no tiene porqué incluir JSON.

Insertar elemento script

El uso de JSONP sólo tiene sentido si se quiere realizar una llamada asíncrona a otro dominio, por ello es necesario manipular el DOM para insertar un elemento <script> en la cabecera de la página, ya que una vez cargado el documento, no es posible escribir en él.

function loadScript (id, src, callback) {

     // Crear elemento
     var script = document.createElement("script");

     // Atributos del script
     script.setAttribute("type", "text/javascript");
     script.setAttribute("src", src + "?callback=" + callback);
     script.setAttribute("id", id);

     // Insertar script en la cabecera
     document.getElementsByTagName("head")[0].appendChild(script);

}

No obstante, es más frecuente utilizar alguna librería de manipulación del DOM como jQuery o Mootools para apoyarse.

Angular JS : Understanding directives

[Fuente: https://github.com/angular/angular.js/wiki/Understanding-Directives]

Generously reshared from AngularUI

This document is a (tangential) attempt to explain how AngularJS directives and the related compiling engine works so that you’re not flailing around like a noodle the first time you try to tackle it yourself.

Injecting, Compiling, and Linking functions

When you create a directive, there are essentially up to 3 function layers for you to define [1]:

myApp.directive('uiJq', function InjectingFunction(){

  // === InjectingFunction === //
  // Logic is executed 0 or 1 times per app (depending on if directive is used).
  // Useful for bootstrap and global configuration

  return {
    compile: function CompilingFunction($templateElement, $templateAttributes) {

      // === CompilingFunction === //
      // Logic is executed once (1) for every instance of ui-jq in your original UNRENDERED template.
      // Scope is UNAVAILABLE as the templates are only being cached.
      // You CAN examine the DOM and cache information about what variables
      //   or expressions will be used, but you cannot yet figure out their values.
      // Angular is caching the templates, now is a good time to inject new angular templates 
      //   as children or future siblings to automatically run..

      return function LinkingFunction($scope, $linkElement, $linkAttributes) {

        // === LinkingFunction === //
        // Logic is executed once (1) for every RENDERED instance.
        // Once for each row in an ng-repeat when the row is created.
        // If ui-if or ng-switch may also affect if this is executed.
        // Scope IS available because controller logic has finished executing.
        // All variables and expression values can finally be determined.
        // Angular is rendering cached templates. It's too late to add templates for angular
        //  to automatically run. If you MUST inject new templates, you must $compile them manually.

      };
    }
  };
})

You can only access data in $scope inside the LinkingFunction. Since the template logic may remove or duplicate elements, you can only rely on the final DOM configuration in the LinkingFunction. You still cannot rely upon children or following-siblings since they have not been linked yet.

Pre vs Post Linking Functions

Anywhere you can use a LinkingFunction(), you can alternatively use an object with a pre and post linking function. Oddly enough, a LinkingFunction() is a PostLinkingFunction() by default:

link: function LinkingFunction($scope, $element, $attributes) { ... }
...
link: {
  pre: function PreLinkingFunction($scope, $element, $attributes) { ... },
  post: function PostLinkingFunction($scope, $element, $attributes) { ... },
}

The difference is that PreLinkingFunction() will fire on the parent first, then child, and so on. A PostLinkingFunction() goes in reverse, firing on the child first, then parent, and so on. Here’s a demo: http://plnkr.co/edit/qrDMJBlnwdNlfBqEEXL2?p=preview

When do I want this reverse PostLinking behavior? Sometimes jQuery plugins need to know the number and size of children DOM element’s (such as slideshows or layout managers like Isotope). There are a few ways to support these:

  • (Worst) Delay the plugin’s execution using $timeout
  • Nested directives. If each child has a directive, it can require: '^parentDirective' which will give you access to the parentDirective controller.
    • If you use the PreLinkingFunction() on parentDirective, you can instantiate the container empty, and use then update it every time the

This does NOT accomodate for async changes such as loading $scope data via AJAX

If you need to wait till your $scope data finishes loading try using ui-if to defer linking of a block of DOM.

$element === angular.element() === jQuery() === $()

To make working with the DOM easier, AngularJS contains a miniaturized version of jQuery called jqlite. This emulates some of the core features of jQuery using an almost identical API as jQuery. Any time you see an AngularJS DOM element, it will be the equivalent to a jQuery() wrapped DOM element.

You do NOT have to wrap AngularJS elements in jQuery()

If you are noticing that the full array of jQuery methods (or plugins) aren’t available on an AngularJS element, it’s because you either forgot to load the jQuery lib, or you forgot to load it BEFORE loading AngularJS. If AngularJS doesn’t see jQuery already loaded by the time AngularJS loads, it will use its own jqlite library instead.

$attributes.$observe()

If you have a sibling attribute that will contain {{}} then the attribute will need to be evaluated and could even change multiple times. Don’t do this manually!

Instead use $attributes.$observe('myOtherAttribute', function(newValue)) exactly as you would have used $scope.$watch(). The only difference is the first argument is the attribute name (not an expression) and the callback function only has newValue (already evaluated for you). It will re-fire the callback every single time the evaluation changes too.

NOTE: This means that you can only access this attribute asynchronously

NOTE: If you want to reliably access the attribute pre-evaluation then you should do it in the CompileFunction

Extending Directives

Lets say you want to use a 3rd-party directive, but you want to extend it without modifying it. There are several ways you can go about doing this.

Global Configurations

Some well-designed directives (such as those found in AngularUI) can be configured globally so that you do not have to pass in your options into every instance.

Require Directives

Create a new directive that assumes the first directive has already been applied. You can require it on a parent DOM element, OR on the same DOM element. If you need to access functionality found in the primary directive, make it exposed via the directive controller (this may require submitting a Pull Request or feature request to the plugin developer).

// <div a b></div>
ui.directive('a', function(){
  return {
    controller: function(){
      this.data = {}
      this.changeData = function( ... ) { ... }
    },
    link: ($scope, $element, $attributes, controller) {
      controller.data = { ... }
    }
  }
})
myApp.directive('b', function(){
  return {
    require: 'a',
    link: ($scope, $element, $attributes, aController) {
      aController.changeData()
      aController.data = { ... }
    }
  }
})

Stacking Directives

You can create a new directive with the exact same name as the original directive. Both directives will be executed. However, you can use the priority to control which directive fires first (again, may require a Pull Request or feature request)

// <div a></div>
ui.directive('a', ... )
myApp.directive('a', ... )

Templating

You can leverage <ng-include> or simply create a directive that generates the HTML with the primary directive attached.

// <div b></div>
ui.directive('a', ... )
myApp.directive('b', function(){
  return {
    template: '<div a="someOptions"></div>'
  }
})

Footnotes

AngularJs: Multidioma

[Fuente : http://www.ng-newsletter.com/posts/angular-translate.html]

Easy global i18n angularJS language translations for your Angular app

As worldwide access to the web increases, we as developers are constantly pressed to make our apps internationally and locally accessible. When a user visits our apps, he or she should be able to switch languages on the fly at runtime.

Given that we are building AngularJS client-side apps, we don’t particularly want the user to have to refresh the page or visit an entirely different URL. Of course, AngularJS could easily accommodate your international audience natively, perhaps by generating different templates for different languages and serving those within the app.

This process can become cumbersome, and what happens when you want to change the layout of the app? Every single template needs to be rebuilt and redeployed. This process should just be easy.

Instead of creating new templates, we’ll use angular-translate, an AngularJS module that brings i18n (internationalization) to your Angular appangularjs-translate requires us to create a JSON file that represents translation data per language. It lazy-loads the language-specific translation data from the server only when necessary.

The library angular-translate comes with built-in directives and filters that make the process of internationalizing apps simple. Let’s get started.

Installation

To use angular-translate, we need to load the angular-translate library. We can install it in several different ways, but we prefer using Bower.

Bower is a front-end package manager. It handles not only JavaScript libraries, but also HTML, CSS, and image packages. A package is simply encapsulated, third-party code that is typically publicly accessible in a repository.

  • Using Bower

We install angular-translate using the normal Bower process:

$ bower install angular-translate

Alternatively, we can download the minified version of angular-translate from github.

Once we’ve installed the latest stable version of angular-translate, we can simply embed it in our HTML document. Just make sure it’s embedded after Angular itself, as it depends on the core angular library.

<script src="path/to/angular.js"></script>
<script src="path/to/angular-translate.js"></script>

Last but not least, our app has to declare angular-translate as a load dependency:

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

Great, we’re now ready to use angular-translate’s components to translate our app!

Teaching your app a new language

Now our app depends upon angular-translate as installed, and our app declares it as a dependency, so we can use it to translate our app’s contents.

First, we need to provide translation material for our app to actually speak a new language. This step actually entails configuring the $translate service through our fresh $translateProvider service.

Training our app to use a new language is simple. Using the config function on our app, we provide the different language translations for our app, i.e. English, German, Hebrew, etc.. First, we inject our $translateProvider in the config function, like so:

angular.module('angularTranslateApp', ['pascalprecht.translate'])
  .config(['$translateProvider', function($translateProvider) {
    // Our translations will go in here
}]);

To add a language, we have to make $translateProvider aware of a translation table, which is a JSON object containing our messages (keys) that are to be translated into (values). Using a translation table enables us to write our translations as simple JSON for loading remotely or setting at compile-time, such as:

{
  'MESSAGE': 'Hello world',
}

In a translation table, the key represents a translation id, whereas the value represents the concrete translation for a certain language. Now add a translation table to your app$translateProvider provides a method called translations(), which takes care of that.

app.config(function ['$translateProvider', ($translateProvider) {
  $translateProvider.translations({
    HEADLINE: 'Hello there, This is my awesome app!',
    INTRO_TEXT: 'And it has i18n support!'
  });
}]);

With this translation table in place, our app is set to use angular-translate. Since we’re adding the translation table at configuration time, angular-translate’s components are able to access it as soon as they are instantiated.

Let’s switch over to our app template. Adding translations in the view layer is as simple as binding our key to the view. Using the translate filter, we don’t even have to engage our controller or services or worry about the view layer: We’re able to decouple the translate logic from any controller or service and make our view replaceable without touching business logic code.

Basically, the translate filter works like so:

<h2>{{ 'TRANSLATION_ID' | translate }}</h2>

To update our example app, we make use of the translate filter:

<h2>{{ 'HEADLINE' | translate }}</h2>
<p>{{ 'INTRO_TEXT' | translate }}</p>

Great! We’re now able to translate our content within the view layer without polluting your controllers logic with translation logic; however, we could achieve the same result without using angular-translate at all, since our app only knows about one language.

Let’s see angular-translate’s real power and learn how to teach our app more than one language.

Multi-language support

You’ve already learned how to add a translation table to your app using $translateProvider.translations().

The $translateProvider knows one language, as we set it with the $translateProvider.translations() method. Now, we can add an additional language in the same way by providing a second translation table.

When we set our first translation table, we can provide it a key (a language key) that specifies the language we’re translating. We can simply add another translation key with another language key.

Let’s update our app to include a second language:

app.config(function ['$translateProvider', ($translateProvider) {
  $translateProvider.translations('en_US', {
    HEADLINE: 'Hello there, This is my awesome app!',
    INTRO_TEXT: 'And it has i18n support!'
  });
}]);

To add a second translation table for another language, let’s say German, just do the same with a different language key:

app.config(function ['$translateProvider', ($translateProvider) {
  $translateProvider.translations('en', {
    HEADLINE: 'Hello there, This is my awesome app!',
    INTRO_TEXT: 'And it has i18n support!'
  })
  .translations('de', {
    HEADLINE: 'Hey, das ist meine großartige App!',
    INTRO_TEXT: 'Und sie untersützt mehrere Sprachen!'
  });
}]);

Now our app knows about two different languages. We can add as many languages as needed, there’s no limit; however, since there are now two languages available, how does our app know which language should to use? angular-translate doesn’t prefer any language until you tell it to do so.

To set a preferred language, we can use the method $translateProvider.preferredLanguage(). This method tells angular-translate which of the registered languages is the one that our app should use, by default. It expects an argument with the value of the language key, which points to a certain translation table.

Now, let’s tell our app that it should use English as its default language:

app.config(function ['$translateProvider', ($translateProvider) {
  $translateProvider.translations('en', {
    HEADLINE: 'Hello there, This is my awesome app!',
    INTRO_TEXT: 'And it has i18n support!'
  })
  .translations('de', {
    HEADLINE: 'Hey, das ist meine großartige App!',
    INTRO_TEXT: 'Und sie untersützt mehrere Sprachen!'
  });
  $translateProvider.preferredLanguage('en');
}]);

Switching the language at runtime

To switch to a new language at runtime, we have to use angular-translate’s $translate service. It has a method uses() that either returns the language key of the currently used language, or, when passing a language key as argument, tells angular-translate to use the corresponding language.

To get a feeling for how this capability works in a real app, add two new translation id’s that represent translations for buttons you’ll add later in your HTML template:

app.config(function ['$translateProvider', ($translateProvider) {
  $translateProvider.translations('en', {
    HEADLINE: 'Hello there, This is my awesome app!',
    INTRO_TEXT: 'And it has i18n support!',
    BUTTON_TEXT_EN: 'english',
    BUTTON_TEXT_DE: 'german'
  })
  .translations('de', {
    HEADLINE: 'Hey, das ist meine großartige App!',
    INTRO_TEXT: 'Und sie untersützt mehrere Sprachen!'
    BUTTON_TEXT_EN: 'englisch',
    BUTTON_TEXT_DE: 'deutsch'
  });
  $translateProvider.preferredLanguage('en');
}]);

Next, implement a function on a controller that uses the $translate service and its uses() method to change the language at runtime. To do that, we’ll inject the $translate service in our app’s controller and add a function on its $scope:

app.controller('TranslateCtrl', ['$translate', '$scope', function ($translate, $scope) {
  $scope.changeLanguage = function (langKey) {
    $translate.uses(langKey);
  };
}]);

Now, let’s reflect this change in the HTML template by adding a button for each language. We’ll also have to set up an ng-clickdirective on each button, which calls the function that changes the language at runtime:

<div ng-controller="Ctrl">
  <button ng-click="changeLanguage('de')" translate="BUTTON_TEXT_DE"></button>
  <button ng-click="changeLanguage('en')" translate="BUTTON_TEXT_EN"></button>
</div>

Et voilà! We now have an app with multi-language support!

Loading languages

What fun would it be if we were going to set the languages statically? We can dynamically load languages thanks to Angular’s$http service, through the $translateProvider’s registerLoader function.

First, we need to install the loader-url extension by setting the loader-url service, which expects that there is a back-end server to send back JSON by handling the lang parameter. If you do have a back end that handles the route with the lang parameter, install the loader-url service with Bower like so:

bower install angular-translate-loader-url

If you prefer to have a service that loads static files, we can use the static-files loader that loads JSON files from a path with language files. Since this router is simpler, we’ll go ahead and install this service through Bower:

bower install angular-translate-loader-static-files

Now, let’s make sure this file is loaded in our view through a script tag:

<script src="/js/angular-translate-loader-url.min.js"></script>

To configure our service to use the static-files loader, we need to tell our $translateProvider to use the loader with a configuration object. The configuration object takes two parameters:

  • prefix – which specifies the file prefix (including file paths)
  • suffix – which specifies the file suffix (usually the extension)

The file loader attempts to fetch files at the following URL path: [prefix]/[langKey]/[suffix]. For instance, if we set our config object as:

$translateProvider.useStaticFilesLoader({
  prefix: '/languages/',
  suffix: '.json'
});

The angular-translate attempts to load the en_US language from /languages/en_US.json. Using the StaticFilesLoader like so gives us the side benefit of lazy-loading$translate will only pull down the language files it needs at runtime.

Of course, using asynchronous loading will cause a flash of untranslated content as the app loads. We can circumvent this side effect by setting a default language that is packaged with the app.

One last cool feature: We can use local storage to store our language files. angular-translate provides the ability to use local storage; this capability can be enabled with one function:

$translateProvider.useLocalStorage();

Conclusion

We’ve covered how to use angular-translate to bring i18n support to your Angular app using$translateProvider.translations() and the translate filter. We’ve also shown how to change the language at runtime using$translate service and its uses() method.

Try out angular-translate; it comes with a lot of really nice built-in features, such as handling pluralization, using custom loaders, and setting translations through a service. The docs are fantastic; we suggest you check them out here.

There are a lot of examples with which you can play directly on the site! There’s also an API Reference that shows all available components and the interfaces you can use to build awesome apps with internationalization support!

Angular JS: Javascript promises

[Fuente:  http://wildermuth.com/2013/8/3/JavaScript_Promises]

En este artículo hablamos sobre el concepto de objecto promise que varias librerias Javascript utilizan (incluyendo AngularJS , jQuery , Dojo y WinJS).

Una promise es un patrón para manejar operaciones asíncronas. El problema es que esencialmente cuando comienzas una operación asíncrona, necesitas ejecutar cierto código cuando la operación se ha completado. El código asíncrono se ha hecho tan común que la mayoría de las librerias javascript han creado una solución pasar los callbacks Pero hay ciertas semejanzas en cómo lo hacen todas. Veamos jQuery como ejemplo:

var $info = $("#info");

$.ajax({
    url:"/echo/json/",
    data: { json: JSON.stringify({"name": "someValue"}) },
    type:"POST",
    success: function(response)
    {
       $info.text(response.name);
    }
});

En este ejemplo puedes ver que jQuery utiliza la propiedad “success” de los settings para especificar el callback. Esto no es un promise aunque sí es una forma de pasar funciones callback. When the ajax call is complete, it calls the success function. Depending on the library that uses asynchronous operations, you might pass in a set of callbacks (e.g. for success or failure). There are a ton of ways to accomplish this.

El patrón promise intenta simplificar este proceso. La operación asíncrona simplemente retorna un objeto llamado una promise.Este objeto promise te permite invocar un método llamado “then” que te permite especificar las funciones a utilizar como callbacks. Veamos como consumir una promise utilizando jQuery como ejemplo:

var $info = $("#info");

$.ajax({
    url: "/echo/json/",
    data: {
        json: JSON.stringify({
            "name": "someValue"
        })
    },
    type: "POST"
})
.then(function (response) {
    $info.text(response.name);
});

Lo que es interesante aquí , es que el objeto que ajax retorna es el objeto xhr que implementa el patrón promise de forma que podemos invocar then como se ha mostrado. El poder de invocar a then es que puedes encadenar varias operaciones y completar la operación invocando “done” como mostramos en el siguiente ejemplo:

var $info = $("#info");

$.ajax({
    url: "/echo/json/",
    data: {
        json: JSON.stringify({
            "name": "someValue"
        })
    },
    type: "POST"
})
.then(function (response) {
    $info.text(response.name);
})
.then(function () {
    $info.append("...More");
})
.done(function () {
    $info.append("...finally!");
});

Because many libraries are starting to take on the promise pattern, handling asynchronous operations should be easier no matter what code you’re writing (e.g. NodeJS, in-browser JS, etc.). But what does a promise look like from the other side?

One important key to the pattern is that the then function can accept two functions. The first is for the success callback; the second for the failure callback like so:

var $info = $("#info");

$.ajax({
    // Change URL to see error happen
    url: "/echo/json/",
    data: {
        json: JSON.stringify({
            "name": "someValue"
        })
    },
    type: "POST"
})
.then(function (response) {
    // success
    $info.text(response.name);
}, 
function () {
    // failure
    $info.text("bad things happen to good developers");
})
.always(function () {
    $info.append("...finally");
});

Notice that in jQuery we’re using a call to always to specify that we want to be called whether the success or failure was called.

Let’s see how using a promise looks. Here is an example from AngularJS:

var m = angular.module("myApp", []);

m.factory("dataService", function ($q) {
    function _callMe() {
        var d = $q.defer();

        setTimeout(function () {
            d.resolve();
            //defer.reject();
        }, 100);

        return d.promise;
    }

    return {
        callMe: _callMe
    };
});

function myCtrl($scope, dataService) {
    $scope.name = "None";
    $scope.isBusy = true;
    dataService.callMe()
      .then(function () {
        // Successful
        $scope.name = "success";
      }, 
      function () {
        // failure
        $scope.name = "failure";
      })
      .then(function () {
        // Like a Finally Clause
        $scope.isBusy = false;
      });
}

AngularJS uses an implementation (see the $q variable) that is started with a call to defer() This returns an object that contains ways to mark a successful or failure condition as well as the promise itself. Notice that in the _callMe function the variable is created by calling $q.defer() then the d.promise is returned from the function so that the caller can call the promise methods (e.g. then). When the actual asynchronous operation is performed (in this case mocked up as a setTimeout call), we can use the resolve method on the defer’d object to tell the promise that we completed successfully (and therefore call the first function in the then method below). If we were to call reject, the second method (the failure call) would be called instead.

You can play with these examples in JSFiddle and see what you can make happen. Promises are a really simple and cool way to handle asynchronicity. What I really like about it is that it simplifies your code (so that you don’t have the triangle of doom when you have to nest callback functions inside each other. This makes it easy.

AngularJs: Single Page Apps with AngularJS Routing and Templating

[Fuente: http://scotch.io/tutorials/javascript/single-page-apps-with-angularjs-routing-and-templating]

Overview

Single page apps are becoming increasingly popular. Sites that mimic the single page app behavior are able to provide the feel of a phone/tablet application. Angular helps to create applications like this easily.

Our Simple App

We’re just going to make a simple site with a home, about, and contact page. Angular is built for much more advanced applications than this, but this tutorial will show many of the concepts needed for those larger projects.

Goals

  • Single page application
  • No page refresh on page change
  • Different data on each page
 While this can be done with just Javascript and AJAX calls, Angular will make this process easier as our app starts growing.

File Structure

- script.js 		<!-- stores all our angular code -->
	- index.html 	<!-- main layout -->
	- pages 	<!-- the pages that will be injected into the main layout -->
			----- home.html
			----- about.html
			----- contact.html

HTML

This is the simple part. We’re using Bootstrap and Font Awesome. Open up your index.html file and we’ll add a simple layout with a navigation bar.

<!-- index.html -->
	<!DOCTYPE html>
	<html>
	<head>
	  <!-- SCROLLS -->
	  <!-- load bootstrap and fontawesome via CDN -->
	  <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" />
	  <link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.0/css/font-awesome.css" />

	  <!-- SPELLS -->
	  <!-- load jquery, bootstrap, and angular via CDN -->
	  <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
	  <script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
	  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
	  <script src="script.js"></script>
	</head>
	<body>

		<!-- HEADER AND NAVBAR -->
		<header>
			<nav class="navbar navbar-default">
			<div class="container">
				<div class="navbar-header">
					<a class="navbar-brand" href="/">Angular Routing Example</a>
				</div>

				<ul class="nav navbar-nav navbar-right">
					<li><a href="#"><i class="fa fa-home"></i> Home</a></li>
					<li><a href="#about"><i class="fa fa-shield"></i> About</a></li>
					<li><a href="#contact"><i class="fa fa-comment"></i> Contact</a></li>
				</ul>
			</div>
			</nav>
		</header>

		<!-- MAIN CONTENT AND INJECTED VIEWS -->
		<div id="main">

			<!-- angular templating -->
			<!-- this is where content will be injected -->

		</div>

		<!-- FOOTER -->
		<footer class="text-center">
			View the tutorial on <a href="http://scotch.io/tutorials/angular-routing-and-templating-tutorial">Scotch.io</a>
		</footer>

	</body>
	</html>

For linking to pages, we’ll use the #. We don’t want the browser to think we are actually travelling to about.html or contact.html.

Angular Application

Module and Controller

We’re going to setup our application. Let’s create the angular module and controller. Check out the docs for more information on each.

First, we have to create our module and controller in javascript. We will do that now in script.js.

// script.js

	// create the module and name it scotchApp
	var scotchApp = angular.module('scotchApp', []);

	// create the controller and inject Angular's $scope
	scotchApp.controller('mainController', function($scope) {

		// create a message to display in our view
		$scope.message = 'Everyone come and see how good I look!';
	});

Let’s add the module and controller to our HTML so that Angular knows how to bootstrap our application. To test that everything is working, we will also show the $scope.message variable that we created.

<!-- index.html -->
	<!DOCTYPE html>

	<!-- define angular app -->
	<html ng-app="scotchApp">
	<head>
	  <!-- SCROLLS -->
	  <!-- load bootstrap and fontawesome via CDN -->
	  <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" />
	  <link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.0/css/font-awesome.css" />

	  <!-- SPELLS -->
	  <!-- load jquery, bootstrap, and angular via CDN -->
	  <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
	  <script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
	  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js"></script>
          <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular-route.js"></script>
	  <script src="script.js"></script>
	</head>

	<!-- define angular controller -->
	<body ng-controller="mainController">

	...

	<!-- MAIN CONTENT AND INJECTED VIEWS -->
	<div id="main">
		{{ message }}

		<!-- angular templating -->
		<!-- this is where content will be injected -->
	</div>

Inside of our main div, we will now see the message that we created. Since we have our module and controller set up and we know that Angular is working properly, we will start working on using this layout to show the different pages.

Injecting Pages into the Main Layout

ng-view is an Angular directive that will include the template of the current route (/home, /about, or /contact) in the main layout file. In plain words, it takes the file we want based on the route and injects it into our main layout (index.html).

We will add the ng-view code to our site in the div#main to tell Angular where to place our rendered pages.

<!-- index.html -->
	...

	<!-- MAIN CONTENT AND INJECTED VIEWS -->
	<div id="main">

		<!-- angular templating -->
		<!-- this is where content will be injected -->
		<div ng-view></div>

	</div>

	...

Configure Routes and Views

Since we are making a single page application and we don’t want any page refreshes, we’ll use Angular’s routing capabilities.

Let’s look in our Angular file and add to our application. We will be using $routeProvider in Angular to handle our routing. This way, Angular will handle all of the magic required to go get a new file and inject it into our layout.

AngularJS 1.2 and Routing The ngRoute module is no longer included in Angular after version 1.1.6. You will need to call the module and add it to the head of your document to use it. This tutorial has been updated for AngularJS 1.2

// script.js

	// create the module and name it scotchApp
        // also include ngRoute for all our routing needs
	var scotchApp = angular.module('scotchApp', ['ngRoute']);

	// configure our routes
	scotchApp.config(function($routeProvider) {
		$routeProvider

			// route for the home page
			.when('/', {
				templateUrl : 'pages/home.html',
				controller  : 'mainController'
			})

			// route for the about page
			.when('/about', {
				templateUrl : 'pages/about.html',
				controller  : 'aboutController'
			})

			// route for the contact page
			.when('/contact', {
				templateUrl : 'pages/contact.html',
				controller  : 'contactController'
			});
	});

	// create the controller and inject Angular's $scope
	scotchApp.controller('mainController', function($scope) {
		// create a message to display in our view
		$scope.message = 'Everyone come and see how good I look!';
	});

	scotchApp.controller('aboutController', function($scope) {
		$scope.message = 'Look! I am an about page.';
	});

	scotchApp.controller('contactController', function($scope) {
		$scope.message = 'Contact us! JK. This is just a demo.';
	});

Now we have defined our routes with $routeProvider. As you can see by the configuration, you can specify the route, the template file to use, and even a controller. This way, each part of our application will use its own view and Angular controller.

Our home page will pull the home.html file. About and contact will pull their respective files. Now if we view our app, and click through the navigation, our content will change just how we wanted.

To finish off this tutorial, we just need to define the pages that will be injected. We will also have them each display a message from its respectiive controller.

<!-- home.html -->
	<div class="jumbotron text-center">
		<h1>Home Page</h1>

		<p>{{ message }}</p>
	</div>


<!-- about.html -->
	<div class="jumbotron text-center">
		<h1>About Page</h1>

		<p>{{ message }}</p>
	</div>


<!-- contact.html -->
	<div class="jumbotron text-center">
		<h1>Contact Page</h1>

		<p>{{ message }}</p>
	</div>

SEO on Single Page Apps

Ideally, this technique would be used for an application after a person has signed in. You wouldn’t really want those pages indexed since they are personalized to that specific user. For example, you wouldn’t want your Reader account, Facebook logged in pages, or Blog CMS pages indexed.

If you did want SEO for you application though, how does SEO work for applications/sites that get their pages built with Javascript? Search enginges have a difficult time processing these applications because the content is built dynamically by the browser and not visible to crawlers.

Making Your App SEO Friendly

Techniques to make Javascript single page applications SEO friendly require regular maintenance. According to the officialGoogle suggestions, you would create HTML snapshots. The basic overview of how it would work is that:

  1. A crawler would find a pretty URL (http://scotch.io/seofriendly#key=value)
  2. The crawler would then ask the server for the contents of this URL (in a special modified way)
  3. Web server returns content using an HTML snapshot
  4. HTML snapshot is processed by the crawler
  5. Search results then show the original URL

For more information on this process, be sure to look at Google’s AJAX Crawling and their guide on creating HTML snapshots.

Conclusion

This was a very simple tutorial on how to get Angular routing to work with a layout and separate views. Now you can go ahead and create larger single page applications. There is much more to learn with Angular and I’ll keep writing about different features along my learning journey of Angular.

If anyone has any suggestions for future Angular articles or different ways to do what we’ve just done here (there are so many ways to write the same thing, it can drive a person insane), sound off in the comments.

Angular JS: UI-bootstrap

Getting started

Dependencies

This repository contains a set of native AngularJS directives based on Bootstrap’s markup and CSS. As a result no dependency on jQuery or Bootstrap’s JavaScript is required. The only required dependencies are:

  • AngularJS (minimal version 1.0.8)
  • Bootstrap CSS (tested with version 3.0.3). This version of the library (0.10.0) works only with Bootstrap CSS in version 3.x. 0.8.0 is the last version of this library that supports Bootstrap CSS in version 2.3.x.

Files to download

Build files for all directives are distributed in several flavours: minified for production usage, un-minified for development, with or without templates. All the options are described and can be downloaded from here.

Alternativelly, if you are only interested in a subset of directives, you can create your own build.

Whichever method you choose the good news that the overall size of a download is very small: <20kB for all directives (~5kB with gzip compression!)

Installation

As soon as you’ve got all the files downloaded and included in your page you just need to declare a dependency on the ui.bootstrap module:

angular.module('myModule', ['ui.bootstrap']);

You can fork one of the plunkers from this page to see a working example of what is described here.

CSS

Original Bootstrap’s CSS depends on empty href attributes to style cursors for several components (pagination, tabs etc.). But in AngularJS adding empty href attributes to link tags will cause unwanted route changes. This is why we need to remove empty href attributes from directive templates and as a result styling is not applied correctly. The remedy is simple, just add the following styling to your application:

.nav, .pagination, .carousel, .panel-title a { cursor: pointer; }

AngularJs: Kickstart Your AngularJS Development with Yeoman, Grunt and Bower

[Fuente: http://www.sitepoint.com/kickstart-your-angularjs-development-with-yeoman-grunt-and-bower/]

Whether you love or hate it, there’s no denying that AngularJS is the framework on every developer’s lips. It may not be for everybody, but AngularJS has a quirky, efficient and powerful feature set. Couple that with a few useful development tools like Yeoman, Grunt and Bower and you’ve got yourself an incredibly fast rapid prototyping process.

What we’ll cover

This AngularJS tutorial will cover:

  • Generating a bare bones AngularJS app with Yeoman
  • Using Grunt to speed up development and help perform repetitive tasks
  • Using Bower to add third party plugins/frameworks
  • Making minor changes to your AngularJS app

Prerequisites

To get the most out of this tutorial we recommend you have the following skills and resources available:

  • A terminal and basic knowledge of the command line
  • NodeJS and NPM installed
  • Fundamental JS, CSS and HTML knowledge

Files

You can find a repo of this tutorial project here.

Let’s get started yo!

Alright, let’s get this thing underway. The first thing you need to do is install Yeoman, Grunt and Bower. We’re going to use the Node Package Manager to do this all at once. In a terminal, run the following:

npm install -g yo grunt-cli bower

As simply as that, we now have a powerful set of tools at our disposal. I’ll explain each one as we use it.

Yeoman

Yeoman is used to generate the scaffolding of your app for you. It’ll create the basic folders, files and configurations to get you up and running quickly. Not only that but there are some great custom generators available to create apps of a particular kind – we’re going to use the nifty AngularJS generator.

One of the best features of Yeoman is the ability to use custom generators. We’re going to intall the AngularJS generator to help us get up and running with Angular as quick as possible.

Run the following to install the AngularJS generator:

npm install -g generator-angular

Now it’s time to generate a shiny new AngularJS application. In a fresh project directory, run:

yo angular <your_app_name>

The generator will ask you a couple of questions. You can answer yes to include Twitter’s bootstrap. Also answer yes to include ngResource. The rest we won’t need for now so answer no.

Sit back (for a few seconds) and watch the generator do its magic. Yeoman will create your files and folders, then it will run bower install (more on this in a moment) and npm install to fetch any dependencies and lastly it’ll perform any mandatory configuration.

What’s in the box?

Let’s take a look at what Yeoman’s given us:

  • .bowerrc
  • .editorconfig
  • .gitattributes
  • .gitignore
  • .jshintrc
  • Gruntfile.js
  • app/
  • component.json
  • karma-e2e.conf.js
  • karma.conf.js
  • node_modules/
  • package.json
  • test/

Let’s go over some of the more important things to notice here:

app/ directory
The app directory contains your static app. It has your html, css and javascript in it and it’s where you’ll spend most of your time developing.

package.json
The package.json file helps npm to identify our project as well as to manage all of it’s dependencies. It can also contain all sorts of other metadata relevant to your project.

node_modules
This one is self explanatory. This is where all the node modules that your project depends on are stored.

Gruntfile.js
The Gruntfile is a javascript file that is responsible for configuring your project as well as any tasks or plugins that your project requires. For instance, your gruntfile might specify that your project uses Uglify and that you want it to run uglify on a particular directory at build time. More about Grunt in a moment.

component.json
The component.json file is used to inform the Bower package manager of your projects dependencies as well as other metadata. In recent versions of Bower this file is called bower.json – more on that in a moment.

.bowerrc
The .bowerrc file is used to pass general config options to bower.

Karma files
Karma is a testing framework. We’ll use it to run a few tests for our Angular app.

Phew! That’s quite a lot to take in – once you get more familiar with the output of a yeoman generator however, you’ll learn to love the fact that it handles all of this for you!

Let’s add a few more things to our project before we start get on to some actual development.

Bower – A package manager for the web

Before we use Bower, there’s a small bit of config we have to do ourselves. Bower recently changed their naming convention of component.json files to bower.json files so we need to bring our code base in line with that.

The first thing we need to do is make a small change to our Bower config in .bowerrc so open it up and add the following line:

  {
      "directory": "app/components",
      "json": "bower.json" // Add this line
  }

What this does, is it tells Bower to use a package’s bower.json file for instructions on how to install that package.

Since we’re using bower for our own project’s dependencies, we’ll need to rename the component.json file in our project root to bower.json as well. A small ask when using such cutting edge technologies 🙂

Bower 

Bower is a package manager. It will help us to quickly find and install our favourite CSS frameworks, javascript libraries and plugins with just a few simple commands.

Ok, let’s give Bower a whirl. Yeoman kindly used bower to install Bootstrap for us earlier, but that was just the Bootstrap CSS. We want all the nifty Javascript widgets as well.

Since we’re building an AngularJS app, we’ll need Bootstrap javascript that works with Angular.

Luckily, the team over at Angular UI have ported all the Bootstrap Javascript into Angular!. Let’s use Bower to install their library.

bower install angular-bootstrap --save

The –save flag tells bower to add this to our bower.json file as a dependency

Fantastic! That was easy wasn’t it? Now, navigate into your app/ directory and let’s see what we’ve got to work with.

Our static app

Take a look at the contents of the app/ directory.

  • favicon.ico
  • index.html
  • robots.txt
  • components/
  • scripts/
  • styles/
  • views/

index.html
This should be familiar to most of you, this is the core html page of your app.

components/ directory
The components directory is like the node_modules directory but for Bower. It’s where all the packages you install with Bower will be kept. AngularUI Bootstrap, for instance, will be in there.

scripts/ directory
Again, familiar territory to most. This is where your apps javascript is stored. Note that libraries such as AngularJS will exist in the components directory, so scripts/ is for your files that you write!

styles/ directory
All your css/sass to make your app look moar pretty.

Views
This nifty folder is where your Angular Templates will reside.

Next up we’ll take a closer look at the AngularJS files

AngularJS

The Yeoman Angular generator has given us the bare essentials: A module, a controller and a view. Let’s take a look at each of those:

The Module: /app/scripts/app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
'use strict';
// Here we set up an angular module. We'll attach controllers and
// other components to this module.
angular.module('testApp', [])
  // Angular supports chaining, so here we chain the config function onto
  // the module we're configuring.
  .config(function ($routeProvider) {
    // We use AngularJS dependency injection to fetch the route provider.
    // The route provider is used to setup our app's routes.
    // The config below simply says when you visit '/' it'll render
    // the views/main.html template controlled by the MainCtrl controller.
    // The otherwise method specifies what the app should do if it doesn't recognise
    // the route entered by a user. In this case, redirect to home.
    $routeProvider
      .when('/', {
        templateUrl: 'views/main.html',
        controller: 'MainCtrl'
      })
      .otherwise({
        redirectTo: '/'
      });
  });

The Controller: /app/scripts/controllers/main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
'use strict';
  // Here we attach this controller to our testApp module
  angular.module('testApp')
 
    // The controller function let's us give our controller a name: MainCtrl
    // We'll then pass an anonymous function to serve as the controller itself.
    .controller('MainCtrl', function ($scope) {
 
      // Using AngularJS dependency injection, we've injected the $scope variable
      // Anything we attach to scope will be available to us in the view.
 
      // In this case, we're attaching a collection of Awesome Things to display
      // in app/views/main.html
      $scope.awesomeThings = [
        'HTML5 Boilerplate',
        'AngularJS',
        'Karma'
      ];
    });

The View: app/views/main.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
  <div class="hero-unit">
    <h1>'Allo, 'Allo!</h1>
    <p>You now have</p>
    <ul>
 
        <!-- Here we use the AngularJS directive: ng-repeat to loop through our awesomeThings
        and print them out as list items using the {{}} bindings -->
        <li ng-repeat="thing in awesomeThings">{{thing}}</li>
    </ul>
    <p>installed.</p>
    <h3>Enjoy coding! - Yeoman</h3>
  </div>
[/js]
 
<strong>The Index File: app/index.html</strong>
1  <!doctype html>
  <html>
    <head>...</head>
    <!-- The ng-app directive tells angular which module we'll use
    for our app. In this case the one defined in scripts/app.js -->
    <body ng-app="testApp">
      ...
      <!-- The ng-view directive specifies that our templates
      (such as views/main.html) will be loaded into this div. -->
      <div class="container" ng-view></div>
 
      <!-- Here we load AngularJS and the AngularJS resource component -->
      <script src="components/angular/angular.js"></script>
      <script src="components/angular-resource/angular-resource.js"></script>
 
      <!-- Here we include our own angular scripts -->
      <!-- build:js scripts/scripts.js -->
      <script src="scripts/app.js"></script>
      <script src="scripts/controllers/main.js"></script>
      <!-- endbuild -->
 
      ...
    </body>
  </html>

Let’s see it in action!

We’re ready to take our first look at our application. Navigate back to the root directory of your app and run:

grunt server

Grunt 
Grunt is a powerful, feature rich task runner for Javascript. In brief, it lets you automate repetitive tasks like compiling coffeescript, minifying css, code validation etc. We’ll be using it to do all of that as well as prepare our code for development and deployment.

Grunt is going to whip through our project folder and prepare everything for us such as compiling our included Bootstrap SASS down to css.

After a few seconds a browser window should pop up with your app running and looking all fancy.

Just to be sure, view the source of the page and take a look at the main.css file that’s included. It should be full of Bootstrap code – thanks to the magic of Bower and Grunt.

Let’s change it up

It’s about time to try our hand at making some changes. Since this is Angular, we’ll start with some AngularJS Testing.

Yeoman was kind enough to generate an example test for our controller, so let’s start there.

We’re going to add another thing to our list of awesome things so open test/spec/controllers/main.js and let’s change our test to expect 4 awesome things instead of 3:

test/spec/controllers/main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
'use strict';
describe('Controller: MainCtrl', function () {
  // load the controller's module
  beforeEach(module('testApp'));
  var MainCtrl,
    scope;
  // Initialize the controller and a mock scope
  beforeEach(inject(function ($controller, $rootScope) {
    scope = $rootScope.$new();
    MainCtrl = $controller('MainCtrl', {
      $scope: scope
    });
  }));
  it('should attach a list of awesomeThings to the scope', function () {
    // Change this line
    expect(scope.awesomeThings.length).toBe(3);
    // To this
    expect(scope.awesomeThings.length).toBe(4);
  });
});

Now we can use another great feature of Grunt:

grunt test

This will run our Karma tests. They should fail because the test expects 4 awesomeThings and we still only have 3. Let’s go fix that to make our tests pass.

Open app/scripts/controllers/main.js and add another awesome thing to the list:

/app/scripts/controllers/main.js

1
2
3
4
5
6
7
8
.controller('MainCtrl', function ($scope) {
  $scope.awesomeThings = [
    'HTML5 Boilerplate',
    'AngularJS',
    'Karma',
    'SitePoint'
  ];
});

Save the file and run the tests again:

grunt test

This time they should pass. Now you can fire up the app in your browser (grunt server) and notice that there’s an additional bullet point. Neat huh?

Using our Bower included package

Let’s use the AngularUI Bootstrap library that we included earlier to turn our list of awesomeThings into a dropdown of awesomeThings.

Important Since Bower is just a package manager, it’s not responsible for adding our files to our index.html file. We need to do that ourselves.

So open up app/index.html and add the following line:

1
<script src="components/angular-bootstrap/ui-bootstrap.js"></script>

Then, as per the Getting Started documentation on AngularUI Bootstrap’s site, we need to add their module as a dependency to our own Angular module

Open app/scripts/app.js and add the ui.bootstrap module as a dependency:

/app/scripts/app.js

1
2
3
4
'use strict';
angular.module('testApp', ['ui.bootstrap'])
...

Alright it’s ready to use. Now we need to make a few changes to our view:

The View: app/views/main.html

1
2
3
4
5
6
7
8
9
10
11
12
<ul>
  <li class="dropdown">
    <a class="dropdown-toggle">
      Click me to see some awesome things!
    </a>
    <ul class="dropdown-menu">
      <li ng-repeat="thing in awesomeThings">
        <a>{{thing}}</a>
      </li>
    </ul>
  </li>
</ul>

We’ve used some bootstrap css classes, and moved our ng-repeat to create menu items instead of just a plain old list.

AngularUI Bootstrap directives work as css classes, so simply by adding the dropdown-toggle class to our tag we’ll have a fully functioning dropdown!

We will need to add the Bootstrap UI module to our tests otherwise they’ll fail so make the following changes:

test/spec/controllers/main.js

1
2
3
4
5
6
7
8
9
10
'use strict';
describe('Controller: MainCtrl', function () {
  // load the controller's module
  beforeEach(module('testApp'));
  // load the BootstrapUI module
  beforeEach(module('ui.bootstrap')); // Add this line
 ...
});

/karma.conf.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Karma configuration
// base path, that will be used to resolve files and exclude
basePath = '';
// list of files / patterns to load in the browser
files = [
  JASMINE,
  JASMINE_ADAPTER,
  'app/components/angular/angular.js',
  'app/components/angular-mocks/angular-mocks.js',
  'app/components/angular-bootstrap/ui-bootstrap.js', // Add this line
  'app/scripts/*.js',
  ...

Run grunt test to make sure everything passes

Now you can open up your app in the browser (grunt server) once more and take a look at your handy work.

Conclusion

Well there you have it! A simple Angular App, a third party JS library, some tests, minification and a whole heap of other goodies with minimal effort!

We’ve only scratched the surface of what’s possible with Yeoman and its fellows – but I hope this will inspire you to whip up a quick AngularJS app the next time you have a great idea!

Look out for more AngularJS tutorials and articles on AngularJS best practices coming soon!

Comments on this article are closed. Have a question about AngularJS? Why not ask it on our forums?

AngularJS: Unit Testing

JavaScript is a dynamically typed language which comes with great power of expression, but it also comes with almost no help from the compiler. For this reason we feel very strongly that any code written in JavaScript needs to come with a strong set of tests. We have built many features into Angular which makes testing your Angular applications easy. So there is no excuse for not testing.

It is all about NOT mixing concerns

Unit testing as the name implies is about testing individual units of code. Unit tests try to answer questions such as “Did I think about the logic correctly?” or “Does the sort function order the list in the right order?”

In order to answer such a question it is very important that we can isolate the unit of code under test. That is because when we are testing the sort function we don’t want to be forced into creating related pieces such as the DOM elements, or making any XHR calls in getting the data to sort.

While this may seem obvious it can be very difficult to call an individual function on a typical project. The reason is that the developers often mix concerns resulting in a piece of code which does everything. It makes an XHR request, it sorts the response data and then it manipulates the DOM.

With Angular we try to make it easy for you to do the right thing, and so we provide dependency injection for your XHR (which you can mock out) and we created abstractions which allow you to sort your model without having to resort to manipulating the DOM. So that in the end, it is easy to write a sort function which sorts some data, so that your test can create a data set, apply the function, and assert that the resulting model is in the correct order. The test does not have to wait for the XHR response to arrive, create the right kind of test DOM, nor assert that your function has mutated the DOM in the right way.

With great power comes great responsibility

Angular is written with testability in mind, but it still requires that you do the right thing. We tried to make the right thing easy, but Angular is not magic. If you don’t follow these guidelines you may very well end up with an untestable application.

Dependency Injection

There are several ways in which you can get a hold of a dependency. You can: 1. Create it using the new operator. 2. Look for it in a well-known place, also known as a global singleton. 3. Ask a registry (also known as service registry) for it. (But how do you get a hold of the registry? Most likely by looking it up in a well known place. See #2.) 4. Expect it to be handed to you.

Out of the four options in the list above, only the last one is testable. Let’s look at why:

Using the new operator

While there is nothing wrong with the new operator fundamentally, a problem arises when calling new on a constructor. This permanently binds the call site to the type. For example, lets say that we try to instantiate an XHR that will retrieve data from the server.

function MyClass() {
  this.doWork = function() {
    var xhr = new XHR();
    xhr.open(method, url, true);
    xhr.onreadystatechange = function() {...}
    xhr.send();
  }
}

A problem surfaces in tests when we would like to instantiate a MockXHR that would allow us to return fake data and simulate network failures. By calling new XHR() we are permanently bound to the actual XHR and there is no way to replace it. Yes, we could monkey patch, but that is a bad idea for many reasons which are outside the scope of this document.

Here’s an example of how the class above becomes hard to test when resorting to monkey patching:

var oldXHR = XHR;
XHR = function MockXHR() {};
var myClass = new MyClass();
myClass.doWork();
// assert that MockXHR got called with the right arguments
XHR = oldXHR; // if you forget this bad things will happen

Global look-up:

Another way to approach the problem is to look for the service in a well-known location.

function MyClass() {
  this.doWork = function() {
    global.xhr({
      method:'...',
      url:'...',
      complete:function(response){ ... }
    })
  }
}

While no new dependency instance is created, it is fundamentally the same as new in that no way exists to intercept the call to global.xhr for testing purposes, other then through monkey patching. The basic issue for testing is that a global variable needs to be mutated in order to replace it with call to a mock method. For further explanation of why this is bad see:Brittle Global State & Singletons

The class above is hard to test since we have to change the global state:

var oldXHR = global.xhr;
global.xhr = function mockXHR() {};
var myClass = new MyClass();
myClass.doWork();
// assert that mockXHR got called with the right arguments
global.xhr = oldXHR; // if you forget this bad things will happen

Service Registry:

It may seem that this can be solved by having a registry of all the services and then having the tests replace the services as needed.

function MyClass() {
  var serviceRegistry = ????;
  this.doWork = function() {
    var xhr = serviceRegistry.get('xhr');
    xhr({
      method:'...',
      url:'...',
      complete:function(response){ ... }
    })
}

However, where does the serviceRegistry come from? If it is: new-ed up, the test has no chance to reset the services for testing. a global look-up then the service returned is global as well (but resetting is easier, since only one global variable exists to be reset).

The class above is hard to test since we have to change the global state:

var oldServiceLocator = global.serviceLocator;
global.serviceLocator.set('xhr', function mockXHR() {});
var myClass = new MyClass();
myClass.doWork();
// assert that mockXHR got called with the right arguments
global.serviceLocator = oldServiceLocator; // if you forget this bad things will happen

Passing in Dependencies:

Last, the dependency can be passed in.

function MyClass(xhr) {
  this.doWork = function() {
    xhr({
      method:'...',
      url:'...',
      complete:function(response){ ... }
    })
}

This is the preferred method since the code makes no assumptions about the origin of xhr and cares instead about whoever created the class responsible for passing it in. Since the creator of the class should be different code than the user of the class, it separates the responsibility of creation from the logic. This is dependency-injection in a nutshell.

The class above is testable, since in the test we can write:

function xhrMock(args) {...}
var myClass = new MyClass(xhrMock);
myClass.doWork();
// assert that xhrMock got called with the right arguments

Notice that no global variables were harmed in the writing of this test.

Angular comes with dependency injection built-in, making the right thing easy to do, but you still need to do it if you wish to take advantage of the testability story.

Controllers

What makes each application unique is its logic, and the logic is what we would like to test. If the logic for your application contains DOM manipulation, it will be hard to test. See the example below:

function PasswordCtrl() {
  // get references to DOM elements
  var msg = $('.ex1 span');
  var input = $('.ex1 input');
  var strength;
 
  this.grade = function() {
    msg.removeClass(strength);
    var pwd = input.val();
    password.text(pwd);
    if (pwd.length > 8) {
      strength = 'strong';
    } else if (pwd.length > 3) {
      strength = 'medium';
    } else {
      strength = 'weak';
    }
    msg
     .addClass(strength)
     .text(strength);
  }
}

The code above is problematic from a testability point of view since it requires your test to have the right kind of DOM present when the code executes. The test would look like this:

var input = $('<input type="text"/>');
var span = $('<span>');
$('body').html('<div class="ex1">')
  .find('div')
    .append(input)
    .append(span);
var pc = new PasswordCtrl();
input.val('abc');
pc.grade();
expect(span.text()).toEqual('weak');
$('body').empty();

In angular the controllers are strictly separated from the DOM manipulation logic and this results in a much easier testability story as the following example shows:

function PasswordCtrl($scope) {
  $scope.password = '';
  $scope.grade = function() {
    var size = $scope.password.length;
    if (size > 8) {
      $scope.strength = 'strong';
    } else if (size > 3) {
      $scope.strength = 'medium';
    } else {
      $scope.strength = 'weak';
    }
  };
}

and the test is straight forward:

var $scope = {};
var pc = $controller('PasswordCtrl', { $scope: $scope });
$scope.password = 'abc';
$scope.grade();
expect($scope.strength).toEqual('weak');

Notice that the test is not only much shorter, it is also easier to follow what is happening. We say that such a test tells a story, rather then asserting random bits which don’t seem to be related.

Filters

Filters are functions which transform the data into a user readable format. They are important because they remove the formatting responsibility from the application logic, further simplifying the application logic.

myModule.filter('length', function() {
  return function(text){
    return (''+(text||'')).length;
  }
});
 
var length = $filter('length');
expect(length(null)).toEqual(0);
expect(length('abc')).toEqual(3);

Directives

Directives in angular are responsible for encapsulating complex functionality within custom HTML tags, attributes, classes or comments. Unit tests are very important for directives because the components you create with directives may be used throughout your application and in many different contexts.

Simple HTML Element Directive

Let’s start with an angular app with no dependencies.

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

Now we can add a directive to our app.

app.directive('aGreatEye', function () {
    return {
        restrict: 'E',
        replace:  true,
        template: '<h1>lidless, wreathed in flame, {{1 + 1}} times</h1>'
    };
});

This directive is used as a tag <a-great-eye></a-great-eye>. It replaces the entire tag with the template<h1>lidless, wreathed in flame, {{1 + 1}} times</h1>. Now we are going to write a jasmine unit test to verify this functionality. Note that the expression {{1 + 1}} times will also be evaluated in the rendered content.

describe('Unit testing great quotes', function() {
    var $compile;
    var $rootScope;
 
    // Load the myApp module, which contains the directive
    beforeEach(module('myApp'));
 
    // Store references to $rootScope and $compile
    // so they are available to all tests in this describe block
    beforeEach(inject(function(_$compile_, _$rootScope_){
      // The injector unwraps the underscores (_) from around the parameter names when matching
      $compile = _$compile_;
      $rootScope = _$rootScope_;
    }));
    
    it('Replaces the element with the appropriate content', function() {
        // Compile a piece of HTML containing the directive
        var element = $compile("<a-great-eye></a-great-eye>")($rootScope);
        // fire all the watches, so the scope expression {{1 + 1}} will be evaluated
        $rootScope.$digest();
        // Check that the compiled element contains the templated content
        expect(element.html()).toContain("lidless, wreathed in flame, 2 times");
    });
});

We inject the $compile service and $rootScope before each jasmine test. The $compile service is used to render the aGreatEye directive. After rendering the directive we ensure that the directive has replaced the content and “lidless, wreathed in flame, 2 times” is present.

Sample project

See the angular-seed project for an example.

AngularJS: End-to-end Testing

[Fuente: http://docs.angularjs.org/guide/dev_guide.e2e-testing]

If you’re starting a new Angular project, you may want to look into using Protractor, as it is going to replace the current method of E2E Testing in the near future.

As applications grow in size and complexity, it becomes unrealistic to rely on manual testing to verify the correctness of new features, catch bugs and notice regressions.

To solve this problem, we have built an Angular Scenario Runner which simulates user interactions that will help you verify the health of your Angular application.

Overview

You will write scenario tests in JavaScript, which describe how your application should behave, given a certain interaction in a specific state. A scenario is comprised of one or more it blocks (you can think of these as the requirements of your application), which in turn are made of commands and expectations. Commands tell the Runner to do something with the application (such as navigate to a page or click on a button), and expectations tell the Runner to assert something about the state (such as the value of a field or the current URL). If any expectation fails, the runner marks the it as “failed” and continues on to the next one. Scenarios may also have beforeEach and afterEach blocks, which will be run before (or after) each it block, regardless of whether they pass or fail.

In addition to the above elements, scenarios may also contain helper functions to avoid duplicating code in the it blocks.

Here is an example of a simple scenario:

describe('Buzz Client', function() {
it('should filter results', function() {
  input('user').enter('jacksparrow');
  element(':button').click();
  expect(repeater('ul li').count()).toEqual(10);
  input('filterText').enter('Bees');
  expect(repeater('ul li').count()).toEqual(1);
});
});

Note that input('user') finds the <input> element with ng-model="user" not name="user".

This scenario describes the requirements of a Buzz Client, specifically, that it should be able to filter the stream of the user. It starts by entering a value in the input field with ng-model=”user”, clicking the only button on the page, and then it verifies that there are 10 items listed. It then enters ‘Bees’ in the input field with ng-model=’filterText’ and verifies that the list is reduced to a single item.

The API section below lists the available commands and expectations for the Runner.

API

Source: https://github.com/angular/angular.js/blob/master/src/ngScenario/dsl.js

pause()

Pauses the execution of the tests until you call resume() in the console (or click the resume link in the Runner UI).

sleep(seconds)

Pauses the execution of the tests for the specified number of seconds.

browser().navigateTo(url)

Loads the url into the test frame.

browser().navigateTo(url, fn)

Loads the URL returned by fn into the testing frame. The given url is only used for the test output. Use this when the destination URL is dynamic (that is, the destination is unknown when you write the test).

browser().reload()

Refreshes the currently loaded page in the test frame.

browser().window().href()

Returns the window.location.href of the currently loaded page in the test frame.

browser().window().path()

Returns the window.location.pathname of the currently loaded page in the test frame.

browser().window().search()

Returns the window.location.search of the currently loaded page in the test frame.

browser().window().hash()

Returns the window.location.hash (without #) of the currently loaded page in the test frame.

browser().location().url()

Returns the $location.url() of the currently loaded page in the test frame.

browser().location().path()

Returns the $location.path() of the currently loaded page in the test frame.

browser().location().search()

Returns the $location.search() of the currently loaded page in the test frame.

browser().location().hash()

Returns the $location.hash() of the currently loaded page in the test frame.

expect(future).{matcher}

Asserts the value of the given future satisfies the matcher. All API statements return a future object, which get avalue assigned after they are executed. Matchers are defined using angular.scenario.matcher, and they use the value of futures to run the expectation. For example:expect(browser().location().href()).toEqual('http://www.google.com'). Available matchers are presented further down this document.

expect(future).not().{matcher}

Asserts the value of the given future satisfies the negation of the matcher.

using(selector, label)

Scopes the next DSL element selection.

binding(name)

Returns the value of the first binding matching the given name.

input(name).enter(value)

Enters the given value in the text field with the corresponding ng-model name.

input(name).check()

Checks/unchecks the checkbox with the corresponding ng-model name.

input(name).select(value)

Selects the given value in the radio button with the corresponding ng-model name.

input(name).val()

Returns the current value of an input field with the corresponding ng-model name.

repeater(selector, label).count()

Returns the number of rows in the repeater matching the given jQuery selector. The label is used for test output.

repeater(selector, label).row(index)

Returns an array with the bindings in the row at the given index in the repeater matching the given jQuery selector. Thelabel is used for test output.

repeater(selector, label).column(binding)

Returns an array with the values in the column with the given binding in the repeater matching the given jQueryselector. The label is used for test output.

select(name).option(value)

Picks the option with the given value on the select with the given ng-model name.

select(name).options(value1, value2…)

Picks the options with the given values on the multi select with the given ng-model name.

element(selector, label).count()

Returns the number of elements that match the given jQuery selector. The label is used for test output.

element(selector, label).click()

Clicks on the element matching the given jQuery selector. The label is used for test output.

element(selector, label).query(fn)

Executes the function fn(selectedElements, done), where selectedElements are the elements that match the given jQuery selector and done is a function that is called at the end of the fn function. The label is used for test output.

element(selector, label).{method}()

Returns the result of calling method on the element matching the given jQuery selector, where method can be any of the following jQuery methods: valtexthtmlheightinnerHeightouterHeightwidthinnerWidth,outerWidthpositionscrollLeftscrollTopoffset. The label is used for test output.

element(selector, label).{method}(value)

Executes the method passing in value on the element matching the given jQuery selector, where method can be any of the following jQuery methods: valtexthtmlheightinnerHeightouterHeightwidthinnerWidth,outerWidthpositionscrollLeftscrollTopoffset. The label is used for test output.

element(selector, label).{method}(key)

Returns the result of calling method passing in key on the element matching the given jQuery selector, where methodcan be any of the following jQuery methods: attrpropcss. The label is used for test output.

element(selector, label).{method}(key, value)

Executes the method passing in key and value on the element matching the given jQuery selector, where methodcan be any of the following jQuery methods: attrpropcss. The label is used for test output.

Matchers

Matchers are used in combination with the expect(...) function as described above and can be negated with not(). For instance: expect(element('h1').text()).not().toEqual('Error').

Source: https://github.com/angular/angular.js/blob/master/src/ngScenario/matchers.js

// value and Object comparison following the rules of angular.equals().
expect(value).toEqual(value)
 
// a simpler value comparison using ===
expect(value).toBe(value)
 
// checks that the value is defined by checking its type.
expect(value).toBeDefined()
 
// the following two matchers are using JavaScript's standard truthiness rules
expect(value).toBeTruthy()
expect(value).toBeFalsy()
 
// verify that the value matches the given regular expression. The regular
// expression may be passed in form of a string or a regular expression
// object.
expect(value).toMatch(expectedRegExp)
 
// a check for null using ===
expect(value).toBeNull()
 
// Array.indexOf(...) is used internally to check whether the element is
// contained within the array.
expect(value).toContain(expected)
 
// number comparison using < and >
expect(value).toBeLessThan(expected)
expect(value).toBeGreaterThan(expected)

Example

See the angular-seed project for more examples.

Conditional actions with element(…).query(fn)

E2E testing with angular scenario is highly asynchronous and hides a lot of complexity by queueing actions and expectations that can handle futures. From time to time, you might need conditional assertions or element selection. Even though you should generally try to avoid this (as it is can be sign for unstable tests), you can add conditional behavior with element(...).query(fn). The following code listing shows how this function can be used to delete added entries (where an entry is some domain object) using the application’s web interface.

Imagine the application to be structured into two views:

beforeEach(function () {
  var deleteEntry = function () {
    browser().navigateTo('/entries');
 
    // we need to select the <tbody> element as it might be the case that there
    // are no entries (and therefore no rows). When the selector does not
    // result in a match, the test would be marked as a failure.
    element('table tbody').query(function (tbody, done) {
      // ngScenario gives us a jQuery lite wrapped element. We call the
      // `children()` function to retrieve the table body's rows
      var children = tbody.children();
 
      if (children.length > 0) {
        // if there is at least one entry in the table, click on the link to
        // the entry's detail view
        element('table tbody a').click();
        // and, after a route change, click the delete button
        element('.btn-danger').click();
      }
 
      // if there is more than one entry shown in the table, queue another
      // delete action.
      if (children.length > 1) {
        deleteEntry();
      }
 
      // remember to call `done()` so that ngScenario can continue
      // test execution.
      done();
    });
 
  };
 
  // start deleting entries
  deleteEntry();
});

In order to understand what is happening, we should emphasize that ngScenario calls are not immediately executed, but queued (in ngScenario terms, we would be talking about adding future actions). If we had only one entry in our table, then the following future actions would be queued:

// delete entry 1
browser().navigateTo('/entries');
element('table tbody').query(function (tbody, done) { ... });
element('table tbody a');
element('.btn-danger').click();

For two entries, ngScenario would have to work on the following queue:

// delete entry 1
browser().navigateTo('/entries');
element('table tbody').query(function (tbody, done) { ... });
element('table tbody a');
element('.btn-danger').click();
 
    // delete entry 2
    // indented to represent "recursion depth"
    browser().navigateTo('/entries');
    element('table tbody').query(function (tbody, done) { ... });
    element('table tbody a');
    element('.btn-danger').click();

Caveats

ngScenario does not work with apps that manually bootstrap using angular.bootstrap. You must use the ng-app directive.

AngularJS : From jQuery to Angular

1. Don’t design your page, and then change it with DOM manipulations

In jQuery, you design a page, and then you make it dynamic. This is because jQuery was designed for augmentation and has grown incredibly from that simple premise.

But in AngularJS, you must start from the ground up with your architecture in mind. Instead of starting by thinking “I have this piece of the DOM and I want to make it do X”, you have to start with what you want to accomplish, then go about designing your application, and then finally go about designing your view.

2. Don’t augment jQuery with AngularJS

Similarly, don’t start with the idea that jQuery does X, Y, and Z, so I’ll just add AngularJS on top of that for models and controllers. This is really tempting when you’re just starting out, which is why I always recommend that new AngularJS developers don’t use jQuery at all, at least until they get used to doing things the “Angular Way”.

I’ve seen many developers here and on the mailing list create these elaborate solutions with jQuery plugins of 150 or 200 lines of code that they then glue into AngularJS with a collection of callbacks and $applys that are confusing and convoluted; but they eventually get it working! The problem is that in most cases that jQuery plugin could be rewritten in AngularJS in a fraction of the code, where suddenly everything becomes comprehensible and straightforward.

The bottom line is this: when solutioning, first “think in AngularJS”; if you can’t think of a solution, ask the community; if after all of that there is no easy solution, then feel free to reach for the jQuery. But don’t let jQuery become a crutch or you’ll never master AngularJS.

3. Always think in terms of architecture

First know that single-page applications are applications. They’re not webpages. So we need to think like a server-side developer in addition to thinking like a client-side developer. We have to think about how to divide our application into individual, extensible, testable components.

So then how do you do that? How do you “think in AngularJS”? Here are some general principles, contrasted with jQuery.

The view is the “official record”

In jQuery, we programmatically change the view. We could have a dropdown menu defined as a ul like so:

<ul class="main-menu">
    <li class="active">
        <a href="#/home">Home</a>
    </li>
    <li>
        <a href="#/menu1">Menu 1</a>
        <ul>
            <li><a href="#/sm1">Submenu 1</a></li>
            <li><a href="#/sm2">Submenu 2</a></li>
            <li><a href="#/sm3">Submenu 3</a></li>
        </ul>
    </li>
    <li>
        <a href="#/home">Menu 2</a>
    </li>
</ul>

In jQuery, in our application logic, we would activate it with something like:

$('.main-menu').dropdownMenu();

When we just look at the view, it’s not immediately obvious that there is any functionality here. For small applications, that’s fine. But for non-trivial applications, things quickly get confusing and hard to maintain.

In AngularJS, though, the view is the official record of view-based functionality. Our ul declaration would look like this instead:

<ul class="main-menu" dropdown-menu>
    ...
</ul>

These two do the same thing, but in the AngularJS version anyone looking at the template knows what’s supposed to happen. Whenever a new member of the development team comes on board, she can look at this and then know that there is a directive called dropdownMenu operating on it; she doesn’t need to intuit the right answer or sift through any code. The view told us what was supposed to happen. Much cleaner.

Developers new to AngularJS often ask a question like: how do I find all links of a specific kind and add a directive onto them. The developer is always flabbergasted when we reply: you don’t. But the reason you don’t do that is that this is like half-jQuery, half-AngularJS, and no good. The problem here is that the developer is trying to “do jQuery” in the context of AngularJS. That’s never going to work well. The view is the official record. Outside of a directive (more on this below), you never, ever, never change the DOM. And directives are applied in the view, so intent is clear.

Remember: don’t design, and then mark up. You must architect, and then design.

Data binding

This is by far one of the most awesome features of AngularJS and cuts out a lot of the need to do the kinds of DOM manipulations I mentioned in the previous section. AngularJS will automatically update your view so you don’t have to! In jQuery, we respond to events and then update content. Something like:

$.ajax({
  url: '/myEndpoint.json',
  success: function ( data, status ) {
    $('ul#log').append('<li>Data Received!</li>');
  }
});

For a view that looks like this:

<ul class="messages" id="log">
</ul>

Apart from mixing concerns, we also have the same problems of signifying intent that I mentioned before. But more importantly, we had to manually reference and update a DOM node. And if we want to delete a log entry, we have to code against the DOM for that too. How do we test the logic apart from the DOM? And what if we want to change the presentation?

This a little messy and a trifle frail. But in AngularJS, we can do this:

$http( '/myEndpoint.json' ).then( function ( response ) {
    $scope.log.push( { msg: 'Data Received!' } );
});

And our view can look like this:

<ul class="messages">
    <li ng-repeat="entry in log">{{ entry.msg }}</li>
</ul>

But for that matter, our view could look like this:

<div class="messages">
    <div class="alert" ng-repeat="entry in log">
        {{ entry.msg }}
    </div>
</div>

And now instead of using an unordered list, we’re using Bootstrap alert boxes. And we never had to change the controller code! But more importantly, no matter where or how the log gets updated, the view will change too. Automatically. Neat!

Though I didn’t show it here, the data binding is two-way. So those log messages could also be editable in the view just by doing this: <input ng-model="entry.msg" />. And there was much rejoicing.

Distinct model layer

In jQuery, the DOM is kind of like the model. But in AngularJS, we have a separate model layer that we can manage in any way we want, completely independently from the view. This helps for the above data binding, maintains separation of concerns, and introduces far greater testability. Other answers mentioned this point, so I’ll just leave it at that.

Separation of concerns

And all of the above tie into this over-arching theme: keep your concerns separate. Your view acts as the official record of what is supposed to happen (for the most part); your model represents your data; you have a service layer to perform reusable tasks; you do DOM manipulation and augment your view with directives; and you glue it all together with controllers. This was also mentioned in other answers, and the only thing I would add pertains to testability, which I discuss in another section below.

Dependency injection

To help us out with separation of concerns is dependency injection (DI). If you come from a server-side language (from Java to PHP) you’re probably familiar with this concept already, but if you’re a client-side guy coming from jQuery, this concept can seem anything from silly to superfluous to hipster. But it’s not. 🙂

From a broad perspective, DI means that you can declare components very freely and then from any other component, just ask for an instance of it and it will be granted. You don’t have to know about loading order, or file locations, or anything like that. The power may not immediately be visible, but I’ll provide just one (common) example: testing.

Let’s say in our application, we require a service that implements server-side storage through a REST API and, depending on application state, local storage as well. When running tests on our controllers, we don’t want to have to communicate with the server – we’re testing the controller, after all. We can just add a mock service of the same name as our original component, and the injector will ensure that our controller gets the fake one automatically – our controller doesn’t and needn’t know the difference.

Speaking of testing…

4. Test-driven development – always

This is really part of section 3 on architecture, but it’s so important that I’m putting it as its own top-level section.

Out of all of the many jQuery plugins you’ve seen, used, or written, how many of them had an accompanying test suite? Not very many because jQuery isn’t very amenable to that. But AngularJS is.

In jQuery, the only way to test is often to create the component independently with a sample/demo page against which our tests can perform DOM manipulation. So then we have to develop a component separately and then integrate it into our application. How inconvenient! So much of the time, when developing with jQuery, we opt for iterative instead of test-driven development. And who could blame us?

But because we have separation of concerns, we can do test-driven development iteratively in AngularJS! For example, let’s say we want a super-simple directive to indicate in our menu what our current route is. We can declare what we want in our view:

<a href="/hello" when-active>Hello</a>

Okay, now we can write a test:

it( 'should add "active" when the route changes', inject(function() {
    var elm = $compile( '<a href="/hello" when-active>Hello</a>' )( $scope );

    $location.path('/not-matching');
    expect( elm.hasClass('active') ).toBeFalsey();

    $location.path( '/hello' );
    expect( elm.hasClass('active') ).toBeTruthy();
}));

We run our test and confirm that it fails. So now we can write our directive:

.directive( 'whenActive', function ( $location ) {
    return {
        scope: true,
        link: function ( scope, element, attrs ) {
            scope.$on( '$routeChangeSuccess', function () {
                if ( $location.path() == element.attr( 'href' ) ) {
                    element.addClass( 'active' );
                }
                else {
                    element.removeClass( 'active' );
                }
            });
        }
    };
});

Our test now passes and our menu performs as requested. Our development is both iterative and test-driven. Wicked-cool.

5. Conceptually, directives are not packaged jQuery

You’ll often hear “only do DOM manipulation in a directive”. This is a necessity. Treat it with due deference!

But let’s dive a little deeper…

Some directives just decorate what’s already in the view (think ngClass) and therefore sometimes do DOM manipulation straight away and then are basically done. But if a directive is like a “widget” and has a template, it should also respect separation of concerns. That is, the template too should remain largely independent from its implementation in the link and controller functions.

AngularJS comes with an entire set of tools to make this very easy; with ngClass we can dynamically update the class; ngBind allows two-way data binding; ngShow and ngHide programmatically show or hide an element; and many more – including the ones we write ourselves. In other words, we can do all kinds of awesomeness without DOM manipulation. The less DOM manipulation, the easier directives are to test, the easier they are to style, the easier they are to change in the future, and the more re-usable and distributable they are.

I see lots of developers new to AngularJS using directives as the place to throw a bunch of jQuery. In other words, they think “since I can’t do DOM manipulation in the controller, I’ll take that code put it in a directive”. While that certainly is much better, it’s often still wrong.

Think of the logger we programmed in section 3. Even if we put that in a directive, we still want to do it the “Angular Way”. It still doesn’t take any DOM manipulation! There are lots of times when DOM manipulation is necessary, but it’s a lot rarer than you think! Before doing DOM manipulation anywhere in your application, ask yourself if you really need to. There might be a better way.

Here’s a quick example that shows the pattern I see most frequently. We want a toggleable button. (Note: this example is a little contrived and a skosh verbose to represent more complicated cases that are solved in exactly the same way.)

.directive( 'myDirective', function () {
    return {
        template: '<a>Toggle me!</a>',
        link: function ( scope, element, attrs ) {
            var on = false;

            $(element).click( function () {
                if ( on ) {
                    $(element).removeClass( 'active' );
                }
                else {
                    $(element).addClass( 'active' );
                }

                on = !on;
            });
        }
    };
});

There are a few things wrong with this. First, jQuery was never necessary. There’s nothing we did here that needed jQuery at all! Second, even if we already have jQuery on our page, there’s no reason to use it here; we can simply use angular.element and our component will still work when dropped into a project that doesn’t have jQuery. Third, even assuming jQuery was required for this directive to work, jqLite (angular.element) willalways use jQuery if it was loaded! So we needn’t use the $ – we can just use angular.element. Fourth, closely related to the third, is that jqLite elements needn’t be wrapped in $ – the element that is passed to thelink function would already be a jQuery element! And fifth, which we’ve mentioned in previous sections, why are we mixing template stuff into our logic?

This directive can be rewritten (even for very complicated cases!) much more simply like so:

.directive( 'myDirective', function () {
    return {
        scope: true,
        template: '<a ng-class="{active: on}" ng-click="toggle()">Toggle me!</a>',
        link: function ( scope, element, attrs ) {
            scope.on = false;

            scope.toggle = function () {
                scope.on = !scope.on;
            };
        }
    };
});

Again, the template stuff is in the template, so you (or your users) can easily swap it out for one that meets any style necessary, and the logic never had to be touched. Reusability – boom!

And there are still all those other benefits, like testing – it’s easy! No matter what’s in the template, the directive’s internal API is never touched, so refactoring is easy. You can change the template as much as you want without touching the directive. And no matter what you change, your tests still pass.

w00t!

So if directives aren’t just collections of jQuery-like functions, what are they? Directives are actually extensions of HTML. If HTML doesn’t do something you need it to do, you write a directive to do it for you, and then use it just as if it was part of HTML.

Put another way, if AngularJS doesn’t do something out of the box, think how the team would accomplish it to fit right in with ngClickngClass, et al.

Summary

Don’t even use jQuery. Don’t even include it. It will hold you back. And when you come to a problem that you think you know how to solve in jQuery already, before you reach for the $, try to think about how to do it within the confines the AngularJS. If you don’t know, ask! 19 times out of 20, the best way to do it doesn’t need jQuery and to try to solve it with jQuery results in more work for you.