7 days of WordPress plugins, themes & templates - for free!* Unlimited asset downloads! Start 7-Day Free Trial
Advertisement
  1. Code
  2. Angular

Extendiendo HTML con las directivas de AngularJS

Scroll to top
Read Time: 10 mins

Spanish (Español) translation by Steven (you can also view the original English article)

Lo principal de AngularJS es que nos permite ampliar las capacidades de HTML para cumplir el propósito de las páginas web dinámicas de hoy. En este artículo, te mostraré cómo puedes usar las directivas de AngularJS para que tu desarrollo sea más rápido, más fácil y tu código sea más fácil de mantener.

Preparación

Paso 1: Plantilla HTML

Para simplificar las cosas, escribiremos todo nuestro código en un archivo HTML. Créalo y coloca la plantilla HTML básica en él:

Ahora agrega el archivo angular.min.js de la CDN de Google en el <head> del documento:

Paso 2: Creando el módulo

Ahora creemos el módulo para nuestras directivas. Lo llamaré example, pero puedes elegir lo que quieras, solo ten en cuenta que usaremos este nombre como espacio de nombres para las directivas que crearemos más adelante.

Coloca este código en una etiqueta script en la parte inferior de la etiqueta <head>:

No tenemos ninguna dependencia, por lo que la matriz en el segundo argumento de angular.module() está vacía, pero no la elimines por completo porque obtendrás un error $injector:nomod, ya que el formulario un argumento de angular.module() recupera una referencia al módulo ya existente en lugar de crear uno nuevo.

También tienes que agregar un atributo ng-app="example" a la etiqueta <body> para que la aplicación funcione. Después de eso, el archivo debería tener este aspecto:

La directiva de atributos: 1337 C0NV3R73R

Primero, crearemos una directiva simple que funcionará de manera similar a ngBind, pero cambiará el texto a leet speak.

Paso 1: Declaración de la directiva

Las directivas se declaran utilizando el método module.directive():

El primer argumento es el nombre de la directiva. Debe estar en camelCase, pero dado que HTML no distingue entre mayúsculas y minúsculas, usarás un formulario en minúscula delimitado por guiones (example-bind-leet) en tu código HTML.

La función pasada como segundo argumento debe devolver un objeto que describa la directiva. Por ahora solo tendrás una propiedad: La función link:

Paso 2: La función link

Puedes definir la función antes de la declaración del 'return' o directamente en el objeto que se devuelve. Se usa para manipular el DOM del elemento al que se aplicó nuestra directiva y se llama con tres argumentos:

$scope es un objeto scope de Angular, $elem es el elemento DOM que coincide con esta directiva (está envuelto en jqLite, el subconjunto de AngularJS de las funciones más utilizadas de jQuery) y attrs es un objeto con todos los atributos del elemento (con nombres normalizados, por lo que example-bind-leet estará disponible como attrs.exampleBindLeet).

El código más simple posible para esta función en nuestra directiva se vería así:

Primero, reemplazamos algunas de las letras en el texto provisto en el atributo example-bind-leet con sus reemplazos de la tabla 'leet'. La tabla se ve así:

Debes colocarlo en la parte superior de tu etiqueta <script>. Como puedes ver, este es el conversor de letras más básico, ya que reemplaza solo diez caracteres.

Luego, convertimos la cadena a leet speak, usamos el método text() de jqLite para ponerlo en el texto interno del elemento que coincide con esta directiva.

Ahora puedes probarlo poniendo este código HTML en el <body> del documento:

La salida debe tener este aspecto:

Pero esto no es exactamente cómo funciona la directiva ngBind. Cambiaremos eso en los próximos pasos.

Paso 3: El objeto scope

En primer lugar, lo que se pasa en el atributo example-bind-leet debe ser una referencia a una variable en el objeto scope actual, no al texto que queremos convertir. Para ello tendremos que crear un ámbito aislado para la directiva.

Podemos lograr eso agregando un objeto scope al valor de retorno de nuestra función de la directiva:

Cada propiedad de este objeto estará disponible en el ámbito de la directiva. Su valor estará determinado por el valor aquí. Si usamos '-' el valor será igual al valor del atributo con el mismo nombre que la propiedad. El uso de '=' le dirá al compilador que esperamos que se pase una variable del alcance actual, que funcionará como ngBind:

También puedes usar cualquier cosa como nombre de propiedad y poner el nombre del atributo normalizado (convertido a camelCase) después de - o =:

Elige lo que funcione mejor para ti. Ahora también tenemos que cambiar la función link para usar $scope en lugar de attr:

Ahora usa ngInit o crea un controlador y cambia el valor del atributo example-bind-leet del div por el nombre de la variable que usaste:

Paso 4: Detectar cambios

Pero todavía no es así como funciona ngBind. Para ver eso, agreguemos un input para cambiar el valor de textToConvert después de que se haya cargado la página:

Ahora, si abres la página e intentas cambiar el valor del input, verás que nada cambia en nuestro div. Esto se debe a que la función link() se llama una vez por directiva en el momento de la compilación, por lo que no puedes cambiar el contenido del elemento cada vez que algo cambia en la función link.

Para cambiar eso usaremos el método $scope.$watch(). Acepta dos parámetros: el primero es la expresión de Angular que se evaluará cada vez que se modifique el scope, el segundo es una función de devolución de llamada que se llamará cuando el valor de la expresión haya cambiado.

Primero, pongamos el código que teníamos en la función link() en una función local dentro de ella:

Ahora, después de esa función, llamaremos a $scope.$watch() así:

Si abres la página ahora y cambias algo en el input, verás que el contenido de nuestro div también cambia, como se esperaba.

La directiva de elementos: Barra de progreso

Ahora escribiremos una directiva que nos creará una barra de progreso. Para hacer eso usaremos un nuevo elemento: <example-progress>.

Paso 1: Estilo

Para que nuestra barra de progreso luzca como tal, tendremos que usar un poco de CSS. Coloca este código en un elemento <style> en el <head> del documento:

Como puedes ver, es bastante básico: usamos una combinación de position: relative y position: absolute para colocar la barra verde y el valor dentro de nuestro elemento <example-progress>.

Paso 2: Propiedades de la directiva

Este requerirá algunas opciones más que el anterior. Echa un vistazo a este código (e insértalo en tu etiqueta <script>):

Como puedes ver, todavía estamos usando un scope (con dos propiedades esta vez: 'value' para el valor actual y 'max' para el valor máximo) y la función link(), pero hay dos propiedades nuevas:

  • restringido: 'E' - Este le dice al compilador que busque elementos en lugar de atributos. Los posibles valores son:
    • 'A': Solo coincide con los nombres de los atributos (este es el comportamiento predeterminado, por lo que no es necesario establecerlo si deseas que solo coincidan los atributos).
    • 'E': solo coincide con los nombres de los elementos.
    • 'C': Solo coincide con los nombres de clase.
  • Puede combinarlos, por ejemplo, 'AEC' coincidiría con los nombres de atributos, elementos y clases.
  • Plantilla: '': esto nos permite cambiar el HTML interno de nuestro elemento (también hay templateUrl si deseas cargar tu HTML desde un archivo separado)

Por supuesto, no dejaremos la plantilla en blanco. Pon este código HTML ahí:

Como puedes ver, también podemos usar expresiones de Angular en la plantilla: percentValue se tomará del scope de la directiva.

Paso 3: La función link

Esta función será similar a la de la directiva anterior. Primero, crea una función local que realizará la lógica de la directiva; en este caso, actualiza percentValue y establece el ancho de div.progressBar:

Como puedes ver, no podemos usar .css() para cambiar el ancho de div.progressBar porque jqLite no admite selectores en .children(). También necesitamos usar Math.min() y Math.max() para mantener el valor entre 0% y 100% - Math.max() devolverá 0 si precentValue es menor que 0 y Math.min() devolverá 100 si percentValue es superior a 100.

Ahora, en lugar de dos llamadas a scope.$watch() (tenemos que estar atentos a los cambios en $scope.value y $scope.max), usemos $scope.$watchCollection(), que es similar pero funciona en colecciones de propiedades:

Ten en cuenta que estamos pasando una cadena que parece una matriz como primer parámetro, no una matriz de JavaScript.

Para ver cómo funciona, primero cambia ngInit para inicializar dos variables más:

Y luego agrega el elemento <example-progress> debajo del div que usamos anteriormente:

El <body> debería verse así ahora:

Y este es el resultado:

Paso 4: Agregando animaciones usando jQuery

Si agregas campos de entrada para progressValue y progressMax así:

Notarás que cuando cambias cualquiera de los valores, el cambio del ancho es inmediato. Para que se vea un poco mejor, usemos jQuery para animarlo. Lo bueno de usar jQuery con AngularJS es que cuando se incluyen etiquetas <script> de jQuery, Angular reemplazará automáticamente jqLite con él, haciendo de $elem un objeto de jQuery.

Entonces, comencemos agregando el script jQuery al <head> del documento, antes que AngularJS:

Ahora podemos cambiar nuestra función updateProgress() para usar el método .animate() de jQuery. Cambia esta línea:

Por esto:

Y deberías tener una barra de progreso bellamente animada. Tuvimos que usar el método .stop() para detener y terminar las animaciones pendientes en caso de que cambiemos algún valor mientras la animación está en progreso (intenta eliminarlo y cambia los valores en las entradas rápidamente para ver por qué era necesario).

Por supuesto, deberías cambiar el CSS y probablemente usar alguna otra función de animación en tu aplicación para que coincida con tu estilo.

Conclusión

Las directivas de AngularJS son una herramienta poderosa para cualquier desarrollador web. Puedes crear un conjunto de tus propias directivas para simplificar e impulsar tu proceso de desarrollo. Lo que puedes crear solo está limitado por tu imaginación, puedes convertir prácticamente todas tus plantillas del lado del servidor a directivas AngularJS.

Enlaces útiles

Aquí hay algunos enlaces a la documentación de AngularJS:

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.