Categorías
Tutorial

Tutorial sobre AngularJS: (7) Bindings

Una de los aspectos más importantes de angular son los bindings, que los los enlaces que las plantillas de angular utilizan para mostrar y sincronizar los datos en el HTML.

 

Como se comentó en el capítulo de arquitectura es muy importante cambiar la mentalidad de lo que normalmente se hace con JavaScript / jQuery. Con jQuery como respuesta a un evento se modifica directamente el DOM de HTML para mostrar la información requerida. Con MVVM / MVW de angularjs la idea es diferente:

  • Para mostrar la información las plantillas de angular hacen binding con los datos del $scope para que se muestren donde se requiere y como se quiere.
  • Para asociar una función JavaScript a los eventos del DOM se utilizan algunas directivas como ngClick que asocian eventos a las funciones que se encargarán de modificar los datos del $scope.

La idea es que los eventos nunca modifiquen directamente el DOM sino los datos contenidos en el $scope. Estos cambios de forma indirecta ya provocarán los cambios al refrescar la parte visual y volver a aplicar la plantilla.

 

Para explicar mejor los cambios voy a explicar los diferentes tipos de bindings y algunos ejemplos que espero sean de utilidad para representar el cambio de mentalidad requerido.

 

 

One-Way Binding

El primer tipo de binding es el One-Way. Este tipo de binding se utiliza para autorefrescar la parte visual frente a cambios en el $scope. El único refresco posible con este tipo es el $scope ⇒ HTML y no al revés.

 

Para implementar esto se puede hacer de dos formas: utilizando la nomenclatura mustache {{ … }} o con la directiva ngBind

ejemplo 1 oneway

Si se ejecuta este código, se puede ver que al arrancar se ve Xavi (dos veces uno por cada tipo de binding) que es lo que contiene nombre, en cambio, al darle al botón cambia automáticamente por Xavi Paper que es el nuevo valor de nombre.

 

¿Cómo funciona esto internamente?

 

Cuando alguien pone {{nombre}} o la directiva data-ng-bind=”nombre” en el DOM esto internamente llama a $watch. Este método tiene dos argumentos, uno es el path de propiedades dentro del $scope que queremos escuchar (en nuestro caso nombre), y el otro es una función que se invoca cada vez que el valor de la propiedad referenciada por el primer argumento cambia. Es decir cada vez que $scope.nombre modifique su valor se ejecutará esta función.

 

Pero para que angular se entere de que el valor de nombre ha cambiado y sea capaz de llamar a la función alguien tiene que llamar a $digest. Este método lo que hace es recorrer todo el $scope y si algún valor ha variado respecto a la anterior ejecución mira los bindings registrados con $watch y lanza la función correspondiente para que actualice el DOM. En el ejemplo de arriba la llamada la realiza ngClick que al terminar siempre llama a $digest.

 

El método $digest es un método interno que nunca debe ser invocado desde JavaScript. Si por algún motivo angularjs no se ha enterado de que el valor a cambiado, hay que llamar $apply que al final acabará llamando a $digest. Un ejemplo en el que hay que invocar a mano a $apply es si en vez de utilizar ngClick de angular nos enganchamos al evento Click utilizando jquery.

 

Aunque estamos comentado que ngBind y el uso de nomenclatura mustache {{…}} hacen lo mismo existe una pequeña diferencia, no tanto por su funcionalidad sino por el efecto que provocan en compilación de la plantilla de angular. Cuando la aplicación ya empieza a ser importante, existe un tiempo que angular invierte en compilar la página y sustituir los {{…}} y los elementos con ngBind por el valor correspondiente. Durante este pequeño tiempo la pàgina ya ha sido recibida y mostrada por el navegador y por tanto se ve lo siguiente:

 

 

ejemplo 1.1 oneway ngbind_mustache1

 

ejemplo 1.1 oneway ngbind_mustache2

La diferencia viene de cómo interpreta HTML los valores sin la acción de angular. Mientras que la directiva ngBind está asociada a un div y este como está vacío no se ve, el texto {{…}} hasta que angular lo sustituya sí es visible en HTML y por tanto se ve con este feo efecto.

 

En angular existe una directiva llamada ngCloak que se utiliza para ocultar también este feo efecto. Esta directiva utilizando css embebido en el propio Angularjs pone el elemento en el que está con “display: none” durante el tiempo de compilación. En varias ocasiones lo hemos probado y ha funcionado perfectamente pero en alguna otra ocasión hemos tenido problemas posiblemente porque todavía no se habia cargado Angularjs, así que hay q usarlo con cautela y probarlo bien.

One-Time Binding (disponible en angularjs +1.3)

Existe una variante de One-Way binding que es mucho más óptima. Este tipo de binding tiene como objetivo mostrar una información y una vez el valor esté mostrado y estabilizado ya nunca más se va a refrescar.

ejemplo 2 onetime

 

Internamente lo que se hace es eliminar el binding una vez mostrado el valor de forma que se liberan los recursos que se encargan de sincronizar los datos.

 

Two-Way Binding

El One-Way y One-Time binding está muy bien para mostrar la información, pero ¿cómo se recogen los datos introducidos de los controles HTML? Para ello existe el Two-Way binding y la directiva ngModel.

Esta directiva se puede asignar a un input, select o textarea y se encarga de detectar cuando el valor que contiene este control cambia y actualizar el valor del $scope correspondiente. Luego lanza en método $digest para que se refresquen todos los valores que sea necesario actualizar. También se encarga de gestionar la validación del control (si lo tiene) y manejar su estado: válido, inválido, limpio, sucio, … pero todo esto se explicará mejor en el capítulo de forms.

ejemplo 3 twoway

Aquí se puede ver un ejemplo donde al modificar el valor del input sin hacer nada se refresca el {{nombre}} y cómo al pulsar el botón se modifican ambos. Viéndose claramente la bidireccionalidad de la comunicación HTML ⇒ $scope y $scope ⇒ HTML.

 

Expresiones

En la directiva ngBind o en la nomenclatura mustache {{…}} hemos visto que se puede poner en nombre de un campo del $scope, pero realmente este es un caso concreto. Aquí se pueden utilizar expresiones sencillas con determinados operadores que nos ayudan a modificar los datos de forma sencilla.

 

Las expresiones pueden contener valores, operadores y variables.

  • Los valores permitidos son entre otros enteros, decimales, cadenas(“…”), …
  • Los operadores permitidos son los operadores:
    • aritméticos (+, -, *, /, %)
    • lógicos (>, <, >=, <=, ==, !=, ===, !==, (…), &&, ||)
    • concatenación (+)
    • búsquedas en arrays ([…])
    • navegaciones a propiedades (.)
    • separación de sentencias (;)
    • funciones (xxx(..))
    • operador ternario (… ? … : …)
    • filtros (|)
  • Las variables haciendo referencia a propiedades del $scope.

 

Aquí podéis ver un esquema bastante representativo y que podéis imprimirlo como documentación de las expresiones permitidas.

http://teropa.info/images/angular_expressions_cheatsheet.pdf.

 

Functions

Un caso especial de expresiones y muy utilizadas son las funciones y por eso le hacemos una mención especial. Estas suelen ser utilizadas para mostrar campos calculados.

Si en el bind de un element se pone la llamada a una función, esta es invocada para mostrar su valor de respuesta con lo que dentro de la función se debe implementar la fórmula para calcular el valor a mostrar.

ejemplo 6 funcion

 

Filtros

Un tipo especial de operador en las expresiones de angular y que merece una detallar son los filtros.

Los filtros son un operador especial que a partir de unas entradas devuelve una salida. Principalmente se utiliza para mostrar información formateada o modificada pero también se pueden concatenar para que la salida de uno sea la entrada de otro.

 

En angular existe ya algunos filtros predefinidos:

  • Formatear valores
    • currency. formatea el número de entrada como moneda según el locale del browser aunque se le puede fijar el tipo de moneda
    • number: formatea un número, especialmente útil para mostrar determinado número de decimales
    • date: formatea fechas según se defina
    • json: devuelve a partir de un objeto javascript con su equivalente json como string
    • lowercase: pasa el texto a minúsculas
    • uppercase: pasa el texto a mayúsculas
  • Filtro o reordenación de colecciones
    • filter: sirve para filtrar colecciones y solo devolver elementos que cumplan determinada condición
    • limitTo: devuelve los primeros o últimos x elementos de un array o string
    • orderBy: ordena un array

ejemplo 4 filtro 

Además de estos filtros predefinidos se pueden crear nuevos filtros personalizados que den funcionalidades no cubiertas:

 

Los posibles usos de filtros pueden ser:

  • Formatear valores
  • Filtrar u ordenar colecciones
  • Crear funcionalidad similar a operadores personalizados

 

Aquí pongo un ejemplo de como pasar la primera letra de una frase a mayúscula. En concreto en el controlador pongo el nombre de xavi en minúscula y si se ejecuta en pantalla se verá con la X mayúscula.

 ejemplo 5 filtro personalizado

Directivas importantes

Hasta ahora hemos comentado mediante bindings como mostrar la información que está en el $scope, y como capturar valores desde los controles de HTML para modificar los valores internos del $scope. Pero ahora nos queda como suscribirnos a los eventos y algunas clases auxiliares para usar los valores del $scope para modificar el href, src, class, style, … de los elementos del DOM

ngClick / ngDblclick

Esta directiva de utilizar para capturar cuando el usuario hace click o doble click sobre el elemento. Dentro del atributo ng-click o ng-dblclick ser debe poner una expresión como las comentadas anteriormente. Aunque lo más lógico es llamar a un método del $scope y que este realice la funcionalidad apropiada.

ngHref / ngSrc

ngHref y ngSrc se utilizan para asignar el href y src a los elementos HTML que les corresponda. La ventaja de utilizar estas directivas en vez de href y src directamente es la misma que utilizar en ngBind: durante la fase de compilación de la plantilla angularjs, el texto del href/src puede no haber sido sustituido todavía con los valores apropiados y por tanto la pulsación del link o la carga de la imagen dará problemas al no encontrar el recurso con el {{..}} dentro de la url.

ngClass / ngStyle

Con ngClass y ngStyle la idea es aplicar un class o un style en función del cumplimiento de una expresión de angularjs.

ngShow / ngHide

Con ngShow y su antagónico ngHide se pretende hacer visible o invisible un elemento en función de una expresión de angularjs.

ngEnabled / ngDisabled

Al igual que los dos anteriores su funcionalidad es habilitar o deshabilitar un elemento en función de una condición.

 

@_PedroHurtado y @XaviPaper

Vínculo hacia el capitulo anterior: (6) Scope

Los enlaces de compra de todos los artículos publicados en este blog son links de afiliados. A ti lo que compres a través de ellos te va a costar lo mismo y a nosotros nos ayuda al sostenimiento de los gastos.

 

Muchas Gracias.

Por Xavier Jorge Cerdá

Ingeniero Informático por la Universidad Politécnica de Valencia, Xavier Jorge (@XaviPaper) trabaja como CTO de Ami2 y lleva más de 13 años vinculado a proyectos de I+D+i con diversas universidades, y desarrollando y arquitecturando soluciones con tecnologías .Net.

2 respuestas a «Tutorial sobre AngularJS: (7) Bindings»

Hola Xavier,

Decirte que me está gustando mucho este tutorial. Recién estoy empezando con este framework y estaba deseando encontrar explicaciones más técnicas a la vez que entendedoras y aquí las estoy encontrando. Me apunto lo del One-time-binding. Está bien saber que existe.

Por cierto, he buscado info sobre la directiva ngVisible y no he encontrado nada. ¿No te estarás refiriéndo a la directiva ngShow?

¡Un saludo y gracias por el blog!

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Uso de cookies

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información.plugin cookies

ACEPTAR
Aviso de cookies