Introducción a AngularJS

Introducción

No cabe duda de que la revolución movil ha cambiado nuestras vida, nuestras costumbres y nuestra forma de interactuar con la tecnología. Esto por supuesto ha originado un cambio en la propia tecnología al que los que estamos en el mundo del desarrollo hemos tenido que adaptarnos, Internet ha desaparecido, ahora es la nube. Ya no construimos aplicaciones web, ahora creamos servicios en la nube, servicios que son accedidos por muchos más usuarios con mucha mayor concurrencia y con muchos tipos de cliente.

Los tiempos en los que escribíamos una aplicación web con una única interfaz de usuario que era accedida siempre desde el mismo tipo de dispositivos ha terminado hace tiempo… Ahora a nuestros servicios se conectan multitud de dispositivos, con diferentes tamaños, capacidades e interfaces de usuario.

Supone un verdadero problema para el desarrollador el generar todas las interfaces para que los usuarios puedan interactuar con su software. Y cuando existe un problema en el mundo del desarrollo ciertas tecnologías surgen para intentar solucionarlo. En el caso de las interfaces de usuario para los servicios en la nube hay una tecnología, o mejor dicho combinación de tecnologías,  que ha sufrido un completo renacimiento debido a esta situación. Hasta el punto de que a día de hoy son pocos los dispositivos capaces de conectarse de forma autónoma que no la entienden en menor o mayor media. Me refiero a HTML y Javascript.

Sin ninguna duda la combinación HTML y Javascript se está convirtiendo en el nuevo estándar de facto para crear interfaces de usuario aplicables a múltiples dispositivos. Puede que no sean la elección más rápida, espectacular o eficiente para una determinada plataforma, pero no cabe duda de que es la que mayor capacidades posee para el conjunto total de plataformas existentes. Y está mejorando día a día.

Por supuesto, con HTML y Javascript solo es difícil construir una aplicación ya que por sí solos son de bastante bajo nivel y carecen de las abstracciones de alto nivel necesarias para facilitar la tarea de programación de interfaces de usuario. Por eso en los últimos tiempos han surgido una enorme cantidad de frameworks de alta nivel tanto HTML como Javascript para facilitar la vida al programador proporcionando  abstracciones de alto nivel orientadas directamente a la construcción y gestión de interfaces de usuario. En este post hablaré de mi framework javascript favorito, AngularJS que rápidamente está ganando muchísima tracción en el mundo del desarrollo frontend.

AngularJS

AngularJS (https://angularjs.org/) es un franework javascript de última generación creado para desarrollar interfaces de usuario usando HTML y Javascript. Es la solución ideal para desarrollar la interfaz de aplicaciones basadas en una arquitectura tipo thin server  o de microservicios, también es una buena opción para aplicaciones reactivas.

Sus creadores han decidido que Angular es un framework MVW (Model View Whatever o Modelo Vista LoQueSea) debido a que lo puedes catalogar como un framework de tipo Model View Controller, o Model View ViewModel. La verdad es que podríamos pasarnos días intentando catalogarlo en uno u otro patrón. Lo cual tiene poca importancia comparado con las ventajas y capacidades que nos proporciona, entre las que podemos citar:

  • Una organización clara y simple de nuestro código javascript. Con abstracciones simples y concretas y utilidades que nos permiten generar grandes aplicaciones basadas en Javascript manteniendo nuestro código DRY y con un nivel de acoplamiento muy bajo
  • Un conjunto de abstracciones muy potente que nos facilitan la codificación y ayudan a seguir un conjunto de buenas prácticas. Por ejemplo las directivas para manipulación del DOM, servicios para lógica de negocio, controllers para la gestión de la interfaz…
  • Una implementación del concepto de modulo que nos permite crear fácilmente código reusable entre aplicaciones
  • Un sistema de Inversión de Control que nos facilita la gestión de las dependencias entre nuestro código y el testing de la misma
  • La posibilidad de crear nuevos componentes visuales y añadir nuevas capacidades a los ya existentes usando directivas
  • Databinding bidireccional entre nuestro código y la interfaz de usuario. Esto significa que ya no tenemos que preocuparnos de sincronizar la interfaz y los datos; con Angular cualquier cambio en los datos modifica automáticamente la interfaz y viceversa, cualquier cambio en la interfaz resultado de una acción del usuario es sincronizado con nuestros datos.
  • Al ser completamente extensible y proporcionar un modelo de programación simple y fácil de utilizar es una herramienta perfecta como framework de frameworks donde podemos utilizarlo para crear nuestro propio paquete de componentes y utilidades. Frameworks de última generación como Ionic o Famo.us han seguido este camino con notable éxito.

Como se ha  dicho anteriormente Angular proporciona una serie de poderosas abstracciones, abstracciones que es necesario entender si queremos utilizarlo con todo su potencial.

  • Controller (Controlador): Es una función javascript responsable de la gestión de una parte de nuestro HTM; es en el controller donde se implementa el comportamiento de la interfaz
  • Scope: Es un objeto javascript usado por los controllers para mantener el estado de la interfaz. Este estado es sincronizado automáticamente con la interfaz a través del data binding. Se puede ver el scope como el pegamento  entre nuestros controllers y la interfaz de usuario, cada cambio en la interfaz es transmitido al scope (y por lo tanto al controller) y cada cambio del scope es transmitido a la interfaz
  • Directives (Directivas): Es la forma que tiene Angular de enseñarle nuevos trucos al HTML. Las directivas son las responsables de la manipulación del DOM en una aplicación angular. Con directivas podemos crear nuevos componentes visuales o añadir nuevas capacidades a los ya existentes, por ejemplo crear un componente datagrid o hacer que un texto tenga una asignación dinámica de CSS dependiendo del estado de una variable en el scope
  • Services (Servicios): Los servicios son funciones javascript que nos permiten encapsular código genérico que probablemente vaya a ser utilizado por varios controllers diferentes. Los servicios no están ligados a ninguna parte en concreto de la interfaz; por ejemplo el código para realizar llamadas HTTP o transformar ciertos datos (por ejemplo fechas). Aunque no sea la única forma los servicios también pueden usarse para transmitir datos entre controllers
  • Filters (Filtros): Usados para modificar temporalmente nuestros datos con propósito de adaptarlos a la interfaz. Los filtros son funciones que reciben los datos y devuelven una nueva representación de dichos datos. Por ejemplo podemos usar un filtro para mostrar una fechas de forma acorde al locale del cliente o para ordenar una lista de usuarios por su nombre como respuesta a un boton. Los filtros no modifican los datos originales.
  • Modules (Modulos): Los módulos son un agrupamiento lógico del resto de conceptos. Un módulo controladores, servicios, directivas filtros, etc relacionados que nos permite utilizarlos como un conjunto y hace más sencillo su rehuso. Los módulos pueden tener dependencias entre ellos de tal forma que un módulo que depende de otro tiene acceso a todos los controladores, servicios, etc que el módulo del que depende proporciona Los módulos son los componentes principales de una aplicación angular bien hecha

Una vez explicados los conceptos más básicos vamos a ver un pequeño ejemplo de aplicación echa con Angular. Para el que quiera jugar un poco con el código este ejemplo está disponible online en este JSFiddle

Ejemplo con Angular
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
<html>
<header>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.0-rc.3/angular.min.js"></script>
</header>
<body ng-controller="exampleCtrl">
<section class="container">
    <div class="form-group">
        <label for="inputName">Your name</label>
        <input type="text"  class="form-control" id="inputName" placeholder="Enter your name" ng-model="name">
    </div>
    <a href="#" ng-class="getClassForButton()" role="button" ng-click="doClick()">Salute</a>
         <p>This is the name you’re typing: {{name}}</p>
    <p>{{salute}}</p>
</section>
<script>
    angular.module('example', [])
            .controller('exampleCtrl', ['$scope', function ($scope) {
                $scope.salute = "I am waiting for your name to properly salute you";
                $scope.doClick = function () {
                    $scope.salute="Hello "+$scope.name+"!"
                }
                $scope.getClassForButton=function(){
                    if(angular.isDefined($scope.name)&&$scope.name.length>3){
                        return "btn btn-primary btn-lg";
                    } else{
                        return "btn btn-primary btn-lg disabled";
                    }
                }
            }]);
    angular.bootstrap(document, ['example']);
</script>
</body>
</html>

Vamos a intentar explicar este código un poquito:

Lo primero de todo es cargar la librería javascript de Angular, y en nuestro caso también hemos cargado el CSS de Bootstrap para hacer que el ejemplo sea un poco bonito a nivel visual.

Vamos a dejar el HTML para más adelante y centrarnos primero en el código javascript definido dentro del tag <script> en la linea 20. Generalmente en una aplicación de verdad nuestro código debería estar contenido en un fichero javascript separado que cargaremos en el head de nuestro documento HTML pero para simplificar en este ejemplo lo hemos incluido en el propio HTML. Queda avisado que la utilizada en este ejemplo no es ni la forma óptima ni la recomendada de organizar nuestra aplicación. Si alguien quiere aprender más sobre cómo organizar una aplicación angular puede esperar a futuros posts o visitar este enlace.

En nuestro código lo primero que hacemos es crear un módulo angular llamado «example» sin dependencias hacia otros módulos. Para ello usamos el método angular.module como se puede ver en la línea 21. El primer parámetro es el nombre del módulo, el segundo una lista de dependencias, en caso de no haber dependencias debemos proporcionar un array vacío.

Ahora que tenemos el módulo es el momento de crear un controller para proporcionar funcionalidad y estado a nuestra aplicación. Como dijimos antes, el estado es mantenido en el scope mientras que la funcionalidad está definida en el controller. Para crear un controller usamos el método controller en nuestro recién creado módulo (hay otras maneras pero esta sigue las buenas prácticas y escala muy bien)  como puede verse en la línea 22.

Este método acepta dos parámetros (de nuevo hay otras formas, pero no son a prueba de compresión y por lo tanto vamos a recomendar usar siempre esta), el primero es el nombre del controller, el segundo es un array donde los primeros elementos son los nombres de las dependencias de nuestro controller como strings y el último elemento es una función que toma como argumentos las dependencias definidas en los primeros elementos. En nuestro ejemplo el controller no tiene más dependencias aparte del scope (que en Angular se denomina $scope) este es el minimo set de dependencias que puede tener un controller. El controller es precisamente esta última función, que Angular se encarga de instanciar y asociar a un elemento del DOM cada vez que lo necesita.

El controller es bastante simple, declaramos una propiedad de tipo String llamada salute en el scope, al declarar esta propiedad nuestra interfaz podrá acceder a ella y, más importante, cualquier cambio en la propiedad será automáticamente reflejado en la interfaz. La consecuencia de esto es que nuestro código solo debe encargarse de modificar la propiedad cuando sea necesario, la interfaz se mantiene en sincronía de forma automática gracias al databinding que nos proporciona Angular.

Aparte de la propiedad hay dos métodos añadidos al scope, el primero modifica la propiedad salute una vez que exista un valor válido para name; el segundo devuelve un string con las clases CSS que queremos asignar al botón de saludar dependiendo del valor de la propiedad name del scope. Básicamente con esto conseguimos que el botón esté deshabilitado mientras no haya un valor correcto en la propiedad name.

La última parte de nuestro código es la llamada al método bootstrap en la línea 36, esto es lo que arranca la aplicación en sí, el primer parámetro es el nodo DOM donde queremos asociar nuestra aplicación, el segundo el nombre del módulo angular que queremos cargar, en nuestro caso es el que acabamos de crear, example.

Vamos ahora al HTML, lo primero que debemos notar es el uso del atributo ng-controller en la línea 8. Así es como se usan las directivas, como atributos, elementos o clases dentro de nuestro HTML. Esta directiva en concreto es la que une un n controller concreto a un elemento del DOM, osea que en nuestro ejemplo lo que estamos haciendo es especificar que el controller exampleCtrl será el encargado de gestionar todo el cuerpo de nuestro HTML.

El siguiente elemento a explicar está en la línea 13 la directiva ng-model en el input. Esta directiva indica a Angular que debe enlazar los contenidos de este elemento con la propiedad name del scope. Esto significa que cualquier valor que le sea asignado a la propiedad se verá reflejado en el elemento y viceversa. Así que si introducimos un valor en el input este valor estará inmediatamente disponible para el controller a través del scope y si modificamos en el controller el scope el input reflejará dicho cambio de forma autmática.

Llegados a este punto es más sencillo entender el método doClick de nuestro controller, carga el contenido insertado en el input a través del scope y crea una nueva propiedad de nombre salute en el scope con dicho valor. Posteriormente la propiedad salute es mostrada en la página mediante el uso de una expresión en la línea 18. Una expresión en el mundo angular es algo similar a un trozo de javascript que se puede insertar en el HTML usando una notación de doble llave. Angular evalúa cada expresión y la sustituye por el resultado de esta evaluación. Aunque esto puede sonar un poco abstracto por el momento nos vale con imaginarnos las expresiones como una forma de mostrar las propiedades asociadas al scope. Si ponemos dentro de una expresión el nombre de una propiedad asociada al scope será automáticamente reemplazada por el valor de dicha propiedad, y cualquier cambio en la propiedad originará una actualización similar en el valor evaluado.

Hay que tener claro sin embargo que las expresiones solo pueden acceder a propiedades y métodos solo y solo si están asociados al scope, no podemos acceder a propiedades o métodos del controller.

Así pues el método doClick modifica la propiedad salute desde su valor inicial a uno que tenga en cuenta la propiedad name, cuando esté método es ejecutado el valor de salute es modificado y por lo tanto nuestra interfaz es actualizada también. Esta es la forma de modificar la interfaz usando Angular, cambiar el valor de las propiedades via Javascript y delegando al sistema de databinding de Angular la actualización de la interfaz en consonancia a los nuevos valores.

El siguiente ejemplo de directivas lo encontramos en la línea 15,  la directiva ng-class nos permite asignar dinámicamente las classes CSS a un elemento HTML, en nuestro caso el boton Salute. Lo que hace este ejemplo es definir como valor de las classes CSS el valor retornado por la función getClassForButton del controller. No hay mucha complicación en el método en sí, si la propiedad name está definida y su longitud es superior a tres asignamos las clases que hacen que nuestro botón esté activo, en caso contrario asignamos las clases para que el botón esté inactivo (por si alguien se lo pregunta estas clases provienen de Bootstrap ). Esta función es automáticamente invocada cada vez que el scope cambia, así que modificar la propiedad name lanza automáticamente la actualización de las clases asociadas al botón.

La última directiva en la línea 16 es probablemente la más fácil de entender. Se trata de la directiva ng-click que ejecuta el método indicado al hacer click sobre el elemento que es aplicada, así es como se asigna comportamiento a un elemento HTML en una aplicación angular.

Resumiendo:

  • El valor del input es ligado a la propiedad name del scope asociado al controller mediante la directiva ng-model
  • El botón Salute tiene dinámicamente asignadas las clases CSS mediante un link al valor retornado por por el método getClassForButton. Este método hace que el botón esté habilitado si la propiedad name tiene más de 3 caracteres de longitud
  • El botón salute invoca el método doClick, este método modifica el valor de la propiedad salute añadiendo el nombre introducido
  • La propiedad salute  se muestra en pantalla utilizando una expresión.

Queda como ejercicio entender como se muestra el nombre que se está introduciendo en pantalla, es muy sencillo una vez comprendido el como funciona el databinding en Angular.

Con esto terminamos esta pequeña introducción a AngularJS aunque apenas hemos arañado la superficie de sus capacidades.

Post By Raul Arabaolaza (3 Posts)

Hay quien programa para crear cosas, yo creo cosas para poder programar

Connect

, , ,

2 Responses to “Introducción a AngularJS”