Material‎ > ‎Software‎ > ‎Angular JS‎ > ‎

AngularJS - Directivas Propias

Introducción

Directiva Hola Mundo

Las directivas se declaran sobre una aplicación angular, así como creábamos un controller antes, también existe un método que permite definir directivas.

app.directive('holaMundo', function() {
    return {
        restrict : 'E',
        template : "Hola Mundo !!!"
    }
});

Este método tiene la forma:

directive(nombre, funcion)

El primer parámetro es el nombre de nuestra directiva. En general se usa camelcase.
El segundo parámetro es una función (o un bloque si quieren llamarle así) que debe devolver un objeto javascript que represente a una "directiva".

Este objeto puede tener varias combinaciones distintas de propiedades.
En este caso estamos configurando dos propiedades:
  • restrict: declara cómo se va a poder usar esta directiva en el html. Es un string. En nuestro caso 'E" indica que se va a usar como si fuera un elemento o tag nuevo de html.
  • template: es el string que va a usar Angular para generar el contenido al encontrar este tag.
Esta nueva directiva la usamos ahora desde el html, así:

<hola-mundo>Se va a reemplazar</hola-mundo>

También podríamos haberla usado así

<hola-mundo></hola-mundo>
<hola-mundo/>

El contenido del tag no se va a ver. Se reemplaza por "Hola Mundo !!!"

Convención de Nombres

Nótese que si bien definimos la directiva como "holaMundo", luego desde el html se utilizó como "hola-mundo". Eso es porque Angular automáticamente traduce un nombre de directiva que esté en camelCase a la notación de palabras (en minúscula) separadas por guión medio.

Ejemplos:
 'errorPanel'... ...<error-panel>
 'menuItemImportante' ... ...<menu-item-importante>

Definición literal vs programática del objeto directiva

Javascript permite definir objetos sin clases, por ser un lenguaje dinámico. Eso quiere decir que si tengo un objeto a través de una variable le puedo agregar nuevos atributos o métodos. Además, también vimos al hablar de JSON que se pueden definir objetos como si fueran mapas. Así definimos nuestra directiva recién:

{
  restrict : 'E',
  template : "Hola Mundo !!!"
}

Como si fuera un mapa. En realidad estamos usando la notación literal de objetos. 
La otra forma de hacer lo mismo, sin usar los literales de objetos sería así:

var directiva = { }
directiva.restrict = 'E'
directiva.template = "Hola Mundo !!!"

Esto se lee: creamos un objeto vacío y lo referenciamos con una nueva variable local. Luego le agregamos dos propiedades con sus valores.

Entonces nuestra directiva podría haberse escrito así completa:

app.directive('holaMundo', function() {
    var directiva = { }
    directiva.restrict = 'E';
    directiva.template = "Hola Mundo !!!"
    return directiva;
});

Quizás sea una cuestión de "gustos". La primer versión con literales parece más concisa, evita la variable local etc. Es, de hecho, más declarativa. Esta segunda opción es más imperativa (manipulamos al objeto incorporando atributos y comportamiento), y posiblemente les resulte más familiar, porque cada linea se parece bastante a las lineas de código que escribían en otros lenguajes.

Restrict

El atributo restrict permite otros valores además de "E".

  • 'E' - matchea con el nombre del tag
  • 'A' - matchea con el nombre de un atributo
  • 'C' - matchea con el nombre de un "class" (CSS). 
Por ejemplo

app.directive('holaMundo', function() {
    return {
        restrict : 'A',
        template : "Hola Mundo !!!"
    }
});

Ahora se usaría:

<div hola-mundo></div>

O bien, con restrict : 'C'

<div class="hola-mundo"></div>

De todas maneras, esta opción está desaconsejada, porque se entremezcla con la mayoría de los frameworks de UI como twitter-bootstrap, jQuery-UI, etc.

Múltiples opciones simultáneas

Podemos igualmente definir que nuestras directivas se puedan usar de más de una forma, incluyendo más de un caracter de los ya vistos.
app.directive('holaMundo', function() {
    return {
        restrict : 'AE',
        template : "Hola Mundo !!!"
    }
});

Esto permite ahora usar nuestra directiva tanto como un tag, como si fuera un atributo de un tag.
Así el usuario finalmente decide usarla como más le guste.

Scope

Ok, todo muy lindo, pero ¿si quiero mostrar información dinámica?
¿Cómo se lleva esto con el scope ? (nota, acá vamos a simplificar un poco. Angular permite más cosas)

Acceso al scope heredado

Desde el template de la directiva podemos tener acceso al scope del controller.

app.directive('holaParametrico', function() {
    return {
        restrict : 'E',
        template : "Hola {{customCtrl.mensaje}} !!!"
    }
});

Luego en nuestro html

<hola-parametrico />

Y en el controller

app.controller('CustomDirectivesCtrl', function () {
   return { 
      mensaje: 'Mundo'
   }
}

Esto produce entonces el texto:

Hola Mundo

Con Scope Propio (pasaje de parámetros)
Este ejemplo lo vamos  encarar al revés. Pensemos que queremos usar nuestro componente así:

<saludo a="juan">

Y que "juan" en nuestro caso está en el scope del controller, y es, de hecho un objeto

app.controller('CustomDirectivesCtrl', function () {
  return { 
    juan: {
      nombre : 'Juan',
      apellido : 'Perez',
      edad : 32
    }
}

Nuestra directiva puede y en este caso debe declarar cómo va a ser su scope y de dónde van a salir sus valores.
app.directive('saludo', function() {
    return {
        restrict : 'E',
        template : 'Hola {{ aQuien.nombre }}!!!',
        scope : {
            aQuien : "=a"
        }
    }
});

La clave es en 
            aQuien : "=a"

Acá estamos diciendo dos cosas:
  • declaramos una variable en el scope "chiquito", propio solo de esta directiva, que se llama "aQuien". Luego la podemos usar desde el template (más arriba)
  • definimos de dónde va a salir el valor de la variable
Lo segundo se hace con "=a"
Quiere decir que el valor va a salir de un atributo del tag, llamado "a"
Si se fijan es lo que usábamos
<saludo a="juan">
Es interesante este mecanismo, porque así nos permite definir directivas que esperan recibir parámetros.

Referencias / Tutoriales



Comments