Tutorial de AngularJS (Parte 1)


Esta la primera entrega del tutorial de AngularJS que voy a realizar. Actualmente no se cuantas entregas le dedicaré para abarcar lo que creo que es básico para su conocimiento y utilización eficiente, pero seguramente estará entre 7 y 8 entregas.

 angularjs

En este tutorial se dará por supuesto un conocimiento básico de HTML y Javascript. Igualmente, cuando se hable de CSS, Bootstrap o jQuery (mínimamente, no es necesario en absoluto para seguir el tutorial), no se especificarán más detalles sobre ellos, puesto que se suponen conocidos.

 

1.- Introducción a AngularJS

Si intentamos resumir de la forma más básica que es AngularJS, se podría decir que es un “framework” Javascript del lado cliente, que es utilizado para añadir interactividad a HTML. En cualquier caso, vamos a ver con más detalle que nos ofrece, cuales son sus ventajas y cuales sus inconvenientes.

 

1.1.- Características de AngularJS

  • AngularJS es un poderoso “framework” Javascript para crear aplicaciones web enriquecidas (RIA, RICH Internet Applications), que no son más que aplicaciones orientadas a Internet, ejecutables en un navegador web moderno, que cumplen muchas de las características de las aplicaciones de escritorio tradicionales, buscando la mejor experiencia y productividad del usuario.
  • AngularJS ofrece a los desarrolladores la posibilidad de escribir aplicaciones del lado cliente (en Javascript, el código se ejecuta en el navegador del usuario), en un patrón limpio MVC (modelo-vista-controlador).
  • Las aplicaciones escritas en AngularJS son compatibles con la mayoría de navegadores web modernos. AngularJS utiliza de forma automática código Javascript compatible con el navegador con el que se esté accediendo a la aplicación.
  • Angular JS es “open source”, completamente libre, y utilizado por miles de desarrolladores de todo el mundo. Está licenciado con la Apache License v2.0.

En resumen, AngularJS es un “framework” Javascript para construir aplicaciones web de gran tamaño y alto rendimiento, logrando a la vez que sean fáciles de mantener.

 

1.2.- Funcionalidades básicas de AngularJS

Vamos a mencionar algunas de las funcionalidades básicas de AngularJS, aunque solo sea de pasada. En todas ellas se entrará mucho más a fondo cuando llegue el momento:

  • “Double data-binding” (doble “atadura”): es la sincronización automática entre los datos del modelo y la vista. Se dice que es “doble” porque funciona en los 2 sentidos, es decir, si algún dato cambia en el modelo, se refleja inmediatamente en la vista, y si cambia en la vista, se tiene en cuenta inmediatamente en el modelo.
  • “Templates” (plantillas): AngularJS se basa en la utilización de plantillas HTML para la información de las vistas. Pueden ser ficheros independientes, o bien estar definidas dentro de otros ficheros HTML principales.
  • “Routing” (rutado): es el concepto de AngularJS para cambiar de vistas. Dado que con AngularJS se intentan construir aplicaciones de página única, se tratará de no cambiar de página con las acciones del usuario, sino simplemente vistas, que pueden corresponder a secciones de una página.
  • “Deep linking” (“enlazado profundo”): AngularJS permite codificar el estado de una aplicación en la URL, de forma que pueda ser copiada o almacenada como favorito, y así ser restaurada al mismo estado simplemente accediendo de nuevo a dicha URL.
  • “Dependency injection” (inyección de dependencias): AngularJS posee un sistema interno de inyección de dependencias que ayuda a los desarrolladores a que la aplicación sea más sencilla de desarrollar, comprender, y testear.

 

1.3.- Ventajas de AngularJS

  • Las aplicaciones AngularJS pueden ejecutarse en la mayoría de navegadores modernos, incluidos los de teléfonos y tablets iOS, Android o Windows Phone.
  • Permite crear aplicaciones de página única de forma muy eficiente, limpia y mantenible.
  • Provee de la capacidad de atadura de datos entre la vista HTML y el código Javascript, lo que ofrece una gran experiencia de uso al usuario.
  • Permite organizar muy bien todo el Javascript de nuestra página, aplicación o sitio web, manteniendo una clara separación de conceptos.
  • Permite crear componentes fácilmente reutilizables.
  • Con AngularJS, el desarrollador tiene que escribir menos código, y sin embargo se consigue mayor funcionalidad.
  • Las vistas son páginas en puro HTML, mientras que los procesos de negocio se escriben en Javascript en los controladores.
  • Se integra a la perfección con jQuery.
  • Es sencillo de realizar “testing” sobre el desarrollo.
  • Existen iniciativas como Ionic, que se basan completamente en AngularJS para conseguir crear aplicaciones móviles híbridas (basadas en HTML5 + CSS + Javascript), simulando de una forma my conseguida a las aplicaciones nativas de iOS o Android.

 

1.4.- Desventajas de AngularJS

  • No seguro: al tratarse de un “framework” únicamente Javascript, las aplicaciones AngularJS no son seguras (su código está expuesto a todos los usuarios que accedan a la misma). Por lo tanto, la autenticación y la autorización en las aplicaciones debe ser realizada en el servidor para mantener un entorno seguro.
  • No degradable: si el entorno de ejecución del usuario deshabilita el uso de Javascript (algo que permiten hacer los navegadores web), la aplicación no funcionará y únicamente se verá el código HTML básico de la página principal.

 

2.- Aplicaciones de página única (Single page application)

Uno de los principales usos y ventajas de AngularJS es que permite realizar las conocidas como aplicaciones web de página única. Vamos a ver de que se trata, y su comparación con el enfoque tradicional.

 

2.1.- Aplicaciones web: enfoque tradicional

El enfoque tradicional de una aplicación, sitio o portal web es acceder a una página de entrada, el servidor manda todo el HTML de dicha página, y se carga completa.

Cuando el usuario hace click en algún enlace, botón de formulario, o cualquier tipo de acción, el servidor vuelve a enviar al navegador del usuario todo el HTML, recursos, etc, de la nueva página a la que se esté accediendo.

Y este proceso se repite una y otra vez, siempre que el usuario ejecute una acción o cambie de página dentro de la aplicación o sitio web.

 

2.2.- Aplicaciones web de página única

En las aplicaciones web de página única toda la aplicación se basa en una única página, dentro de la cual se van cambiando los contenidos, ya sean en una parte de dicha página, o bien a nivel de la página completa.

Al acceder a la página de entrada, el servidor envía al navegador todo el HTML y recursos de dicha página, y se carga completa. Pero cuando el usuario hace click en algún enlace, botón del formulario, o cualquier tipo de acción, el servidor responderá al navegador únicamente con lo necesario para actualizar el contenido de la página, que la mayoría de los casos únicamente serán datos JSON. La página ya cargada y su código Javascript asociado se encargarán de hacer lo necesario para presentar estos nuevos datos.

 

3.- Funcionamiento de AngularJS frente a jQuery o solo Javascript

Gracias a Raúl Expósito por su excelente artículo del cual está sacado este ejemplo.

Vamos a realizar una página muy simple, que toma un valor en un campo de texto de un formulario, y lo muestra en pantalla, para ver como se haría con Angular, jQuery, o únicamente Javascript. Esto puede servir simplemente de ejemplo para comparar la dificultad y la estructura del código básico entre las 3 opciones.

 

3.1.- Javascript

Usando únicamente Javascript, le indicaremos a nuestro campo de entrada incluido en el formulario que invoque a la función encargada de actualizar la salida cada vez que se pulse una tecla. El elemento se pasa a sí mismo como argumento en la función.

En la función de Javascript buscamos el elemento “output" y cambiamos el “innerHTML" de dicho elemento para que tenga el valor de nuestro campo de entrada.

Utilizando únicamente Javascript, el código Javascript y la presentación HTML son muy dependientes el uno del otro. Esto se conoce como un “alto acoplamiento” entre la presentación y el código, lo que hace difícil actualizar y mantener los componentes de nuestra aplicación.

 

HTML

<!DOCTYPE html>
<html>
 <head></head>
 <body>
  <div>
   Enter your name:
   <input type="text" onkeyup="updateOutput(this)"></input>
  </div>
  <div id="output">Hello</div>
 </body>
</html>

 

Javascript

function updateOutput(elem) {
 var name = elem.value;
 var outputElement = document.getElementById("output");
 outputElement.innerHTML = "Hello " + name;
}

 

3.2.- jQuery – Javascript no intrusivo

Una de las ideas que persigue el javascript no intrusivo consiste en lograr que el marcado de las páginas describa únicamente la estructura del documento, y no su funcionalidad.

Generalmente, cuando usamos jQuery y queremos hacer un cambio en una página, usamos un “selector” para buscar un elemento en la página. Tras ello modificamos directamente el elemento y la página se actualiza.

Esta forma de manipular directamente los elementos del árbol DOM se conoce como estilo “imperativo”. Convierte el problema del acoplamiento bidireccional entre la presentación y el código en un acoplamiento unidireccional en aquellos lugares donde hayas especificado programáticamente los identificadores o las clases CSS.

Uno de los mayores problemas cuando se construyen aplicaciones web con jQuery es que pasamos mucho tiempo lidiando con el marcado. El marcado simplemente define cómo ver nuestros datos así que sería estupendo si nuestro código sólo se encargase de los datos y la presentación se actualizase ella sola.

 

HTML

<!DOCTYPE html>
<html>
 <head>
  <script src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
 </head>
 <body>
  <div>
   Enter your name:
   <input name="your-name" id="your-name" type="text"></input>
  </div>
  <div id="output">Hello</div>
 </body>
</html>

 

Javascript

$('#your-name').bind('input', function() {
 var name = $(this).val();
 $('#output').html("Hello " + name);
});

 

3.3.- AngularJS

Esta es la clase de problemas que AngularJS trata de resolver. Vamos a implementar nuestro ejemplo usando AngularJS.

En este ejemplo, simplemente tenemos que indicar que vamos a crear una aplicación AngularJS llamada “myApp”, asociar un nombre de variable a la entrada mediante “ng-model”, y utilizar el valor de dicha variable en la salida mediante la expresión “{{name}}”. Angular se encarga de todo lo demás, puesto que como veréis, el código Javascript es prácticamente inexistente (simplemente lo básico y fundamental para inicializar el módulo con el nombre de nuestra aplicación).

 

HTML

<!DOCTYPE html>
<html>
 <head>
  <script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.1/angular.min.js"></script>
 </head>
 <body ng-app="myApp">
  <div>
   Enter your name:
   <input type="text" ng-model="name"></input>
  </div>
  <div>Hello {{name}}</div>
 </body>
</html>

 

Javascript

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

 

4.- Conceptos básicos de AngularJS (I)

Y has aquí llegan los apartados en los que se intenta convencer de que merece la pena aprender y utilizar AngularJS. Desde ahora empezamos con los temas importantes, y este de los conceptos básicos es algo que hay que dominar para saber utilizar AngularJS de forma eficiente. Así que comenzamos…

 

4.1.- “Directives” – Directivas (D)

Una “directiva” es un marcador en una etiqueta HTML que indica a AngularJS que debe ejecutar una referencia a un código Javascript. Es decir, las “directivas” no son más que etiquetas HTML, ya sean directamente “elementos”, o bien “atributos” para dichos elementos. AngularJS provee de muchas directivas nativas (que digamos extienden aquellas de las que dispone HTML), y aparte por supuesto permite crear las nuestras propias.

<div ng-app="" ng-init="firstName='John'">
 <p>The name is <span ng-bind="firstName"></span></p>
</div>

En el código HTML anterior, “ng-app”, “ng-init” o “ng-bind” son directivas nativas de AngularJS de tipo “atributo”.

 

4.2.- “Modules” – Módulos (M)

Los “módulos” son los trozos de código que forman una aplicación AngularJS (en la mayoría de nuestros ejemplos, las aplicaciones estarán formadas por un único “módulo”, que a su vez podrá importar otros ya existentes para utilizarlos).

Los “módulos” son la forma de encapsular el código Javascript por parte de AngularJS. Permiten hacer nuestro código más fácil de mantener, testear y leer.

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

En el código Javascript anterior, se declara el módulo “myApp”.

 

4.3. “Expressions” – Expresiones (E)

Las “expresiones” de AngularJS nos permiten introducir e incluso evaluar valores dinámicos en el código HTML, aprovechando el “double binding” (a partir de ahora lo llamaremos simplemente “binding”).

Las “expresiones” nos permiten trabajar con cualquier tipo de datos, como números:

<div ng-app="" ng-init="cantidad=1;precio=5">
 <p>Total en euros: {{ cantidad * precio }}</p>
</div>

O con cadenas de texto:

<div ng-app="" ng-init="nombre='Paco';apellido='García'">
 <p>El nombre es {{ nombre + ' ' + apellido }}</p>
</div>

O con “arrays”:

<div ng-app="" ng-init="frutas=['manzana','sandia','naranja']">
 <p>Las fruta es {{ frutas[2] }}</p>
 <!-- El resultado será: "La fruta es naranja" -->
</div>

O con objetos:

<div ng-app="" ng-init="coche={marca:'Renault',modelo:'Megane'}">
 <p>La marca del coche es {{ coche.marca }}</p>
 <!-- El resultado será: "La marca del coche es Renault" -->
</div>

 

4.4.- “Controllers” – Controladores (C)

Los “controladores” son funciones Javascript donde definimos el comportamiento de la aplicación, mediante otras funciones y valores internos. Son la base de nuestros “módulos” o aplicaciones AngularJS.

Los “controladores” se asocian a secciones de la página HTML (al “html” completo, al “body” completo, o a un “div” concreto, etc). Las funciones y variables definidas en ellos solo son accesibles dentro de esa sección de la página HTML. Es decir, un “controlador” asignado al “body” de una página hará que sus funciones y variables sean accesibles desde todo el “body” de la página, mientras que un “controlador” asignado a un “div” concreto de la página hará que sus funciones y variables solo sean accesibles dentro de dicho “div”, nunca fuera.

Para asignar un “controlador” a una sección del HTML se utiliza la “directiva” nativa de AngularJS “ng-controller”.

<div ng-app="myApp" ng-controller="myCtrl">
 First Name: <input type="text" ng-model="firstName"><br>
 Last Name: <input type="text" ng-model="lastName"><br>
 <br>
 Full Name: {{firstName + " " + lastName}}
</div>
<script>
 var app = angular.module('myApp', []);
 app.controller('myCtrl', function($scope) {
  $scope.firstName= "John";
  $scope.lastName= "Doe";
 });
</script>

 

4.5.- “Filters” – Filtros (F)

Los “filtros” son funciones Javascript que, aplicadas en nuestro HTML, permiten formatear un dato y crear una determinada salida con él.

Normalmente, se llama a un “filtro” mediante un “pipe” (carácter “|”), cogiendo como entrada la salida de una determinada expresión, y generando una salida con un formato u orden diferente:

{{ data | filter:options }}

Existe una gran cantidad de filtros nativos en AngularJS, que permiten formatear monedas, fechas o mayúsculas o minúsculas. E igualmente permiten filtrar datos respecto al número de caracteres de una cadena, al orden, o a subconjuntos de los mismos.

  • “currency”: coge una cifra y la convierte a 2 decimales y el símbolo de la moneda utilizada
    {{ store.product.price | currency }}
  • “date”: permite formatear fechas en función de las opciones utilizadas
    {{ '1388123412323' | date:'MM/dd/yyyy @ h:mma' }}
  • “uppercase”: convierte una cadena a mayúsculas
    {{ 'octagon gem' | uppercase }}
  • “lowercase”: convierte una cadena a minúsculas
    {{ 'PRIME Gem' | uppercase }}
  • “limitTo”: limita el número de caracteres de una cadena o un “array” (esto permite que se pueda aplicar a bucles “ng-repeat” para limitar el número de elementos que se muestra en dicho bucle
    {{ 'My Description' | limitTo:8 }}
    <li ng-repeat="product in store.products | limitTo:3">
  • “orderBy”: ordena los elementos de un “array” en base a un cierto criterio, que puede ser aplicado de forma creciente (de menor a mayor) o de forma decreciente (de mayor a menor, con un signo “-” delante)
    <li ng-repeat="product in store.products | orderBy:'-price'">
    <li ng-repeat="product in store.products | orderBy:'price'">
  • “filter”: selecciona un subconjunto de elementos de un “array”:
    <li ng-repeat="alumno in alumnos | filter:nombre | orderBy:'pais'">

 

5.- Principales directivas nativas de AngularJS (I)

Vamos a ir viendo las principales directivas nativas que nos ofrece AngularJS, ya que muchas de las funcionalidades y ventajas que nos ofrece AngularJS están asociadas directamente al uso de estas directivas.

Antes de seguir, es importante aclarar que existen 2 tipos de nomenclaturas diferentes para las directivas de AngularJS, pero ya se use una u otra, se referirá siempre a la misma directiva.

  • la nomenclatura “ng-xxxx” se utiliza en el código HTML, para hacer uso de una directiva.
  • mientras que la nomenclatura “ngXxxx” se utiliza en el código Javascript, cuando se define dicha directiva.

Es por esto que en la web de AngularJS, las directivas suelen utilizar la nomenclatura “ngXxxx”, puesto que ellos han creado dichas directivas en el código fuente de AngularJS, definiéndolas en Javascript de esa forma. Sin embargo, nosotros las veremos mucho más a menudo como “ng-xxxx”, ya que haremos uso de ellas en nuestras páginas HTML, y para ello se hace utilizando esta nomenclatura.

La mayoría de las directivas nativas de AngularJS son directivas “de atributo”. Es decir, se utilizan como “atributos” de elementos nativos de HTML.

NOTA: las directivas nativas de atributo de AngularJS empiezan por “ng-“. HTML5 permite atributos extendidos que comienzan por “data-“, pero no dice nada del prefijo “ng-“. Por lo tanto, si queremos que nuestra página realizada con AngularJS sea validada con HTML5, podemos utilizar las directivas de atributo de AngularJS como “data-ng-xxxx”.

 

5.1.- ngApp / ng-app

  • Tipo de directiva: atributo.
  • Enlace a la API:  ngApp

Esta directiva asigna una aplicación, construida a partir de un “módulo” de AngularJS, a un elemento de la página HTML. Normalmente, este elemento se considera el “elemento raíz” de la aplicación, y suele normalmente el elemento “body”, o en algunos casos el elemento “html”. Pero nada impide que se pueda asignar a un elemento más interno en la página, teniendo en cuenta que de esa forma, únicamente lo contenido dentro de dicho elemento podrá hacer uso de las características de una aplicación AngularJS.

<body ng-app="MyAngularApp">

 

5.2.- ngBind / ng-bind

  • Tipo de directiva: atributo.
  • Enlace a la API: ngBind

Esta directiva nos permite, simplemente, obtener el valor de una variable Javascript del ámbito del controlador asignado a la sección HTML en la que estemos.

Como ya hemos visto antes las “expresiones”, “ng-bind” es lo mismo que utilizar una “expresión” con el nombre de la variable. Por esto mismo, el uso de “ng-bind” no está muy extendido, puesto que siempre suele hacerse mediante la “expresión” equivalente:

<p>The name is <span ng-bind="firstName"></span></p>
<p>The name is {{ firstName }}</p>

 

5.3.- ngShow / ng-show

  • Tipo de directiva: atributo.
  • Enlace a la API: ngShow

Esta directiva aplicada sobre una etiqueta o elemento HTML hace que este solo se muestre en pantalla si la expresión aplicada a la directiva es “true”. Por lo tanto, nos sirve para mostrar u ocultar cosas en función de valores de variables de nuestro ámbito, que podemos evaluar en una expresión.

<div ng-show="myValue">
 <!-- content -->
</div>

5.4.- ngHide / ng-hide

  • Tipo de directiva: atributo.
  • Enlace a la API: ngHide

Esta directiva aplicada sobre una etiqueta o elemento HTML hace que este se oculte en pantalla si la expresión aplicada a la directiva es “true”. Por lo tanto, es exactamente la funcionalidad opuesta a la anterior directiva “ng-hide”, e igualmente nos sirve para mostrar u ocultar cosas en función de valores de variables de nuestro ámbito, que podemos evaluar en una expresión.

<div ng-hide="myValue">
 <!-- content -->
</div>

 

5.5.- ngRepeat / ng-repeat

  • Tipo de directiva: atributo.
  • Enlace a la API: ngRepeat

Esta directiva aplicada sobre una etiqueta o elemento HTML la repite (al elemento y a todo lo que contenga en su interior) de la misma forma que hace un bucle “for” aplicado a la expresión de la directiva.

Por lo tanto, esta directiva es básica para implementar listas, de la misma forma que haríamos mediante un bucle “for” en código, para aplicar principalmente sobre “arrays” y recorrer de esta forma todos sus elementos.

<div ng-repeat="product in store.products">
 <h1>{{product.name}}</h1>
</div>

 

5.6.- ngSrc / ng-src

  • Tipo de directiva: atributo.
  • Enlace a la API: ngSrc

Esta directiva sirve para expresar una ruta a una imagen desde una variable de nuestro controlador.

Es necesaria porque no se puede utilizar el atributo “src” tradicional de HTML para acceder a una imagen con una ruta almacenada en una variable de nuestro controlador, pues esto producirá un error, ya que el navegador intentará acceder a dicha imagen antes de haber procesado el valor de la variable en Javascript, produciendo un fallo en la carga de la imagen, y mostrando el típico icono de imagen no existente.

Por lo tanto, siempre que queramos incluir una imagen en nuestra página y la ruta esté en una variable de nuestro controlador, es necesario utilizar “ng-src” en lugar de únicamente “src”. De esta forma, la carga de la imagen no se intentará hasta que el valor de la expresión que haya en “ng-src” esté disponible.

<img ng-src="{{ product.images[0].full}}" />

 

5.7.- ngClick / ng-click

  • Tipo de directiva: atributo.
  • Enlace a la API:  ngClick

Esta directiva permite ejecutar una expresión asignada a la misma cuando se hace “click” sobre el elemento en que está aplicada. La expresión asignada puede ser simplemente cambiar de valor una variable, pero normalmente siempre se hará mediante la llamada a una función de nuestro controlador.

<a href ng-click="tab = 2">Description</a>
<a href ng-click="asignTab(2)">Description</a>

 

5.8.- ngInit / ng-init

  • Tipo de directiva: atributo.
  • Enlace a la API: ngInit

Esta directiva permite inicializar valores para las variables desde el código HTML.

NOTA: esta directiva solo debe ser utilizada para inicializar bucles de “ngRepeat” de la forma que nos interese, pero no debe ser utilizada simplemente para inicializar valores de variables normales. La inicialización de los valores de variables normales se debe realizar dentro del código de nuestro controlador.

<div ng-repeat="innerList in list" ng-init="outerIndex = $index">
 <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
  <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
 </div>
</div>

 

5.9.- ngClass / ng-class

  • Tipo de directiva: atributo.
  • Enlace a la API: ngClass

Esta directiva permite especificar la clase (“class”) de CSS es un determinado elemento HTML, en función de una expresión. Si la expresión asignada es “true”, el elemento tomará la clase especificada. Si no, no la tomará.

En el siguiente ejemplo, el elemento “li” tomará la clase “active” si la variable “tab” es igual a 3. Si no, no tomará la clase “active”:

<li ng-class="{ active:tab === 3 }">

 

5.10.- ngController / ng-controller

  • Tipo de directiva: atributo.
  • Enlace a la API: ngController

Esta directiva permite asociar un controlador Javascript a la sección o plantilla de la página HTML a la que se está aplicando. De esta forma, el ámbito, y todos los métodos y variables incluidos en el controlador, podrán ser utilizados dentro de dicha sección o plantilla HTML.

<div ng-controller="ExampleController">