angular y el cacao de las recetas I

Qué son y cómo funcionan las recetas de angular

Cezanne

archivado en: JavaScript / 22 febrero, 2015 / taller:

Uno de los temas más complicados de angular es la diferencia entre las distintas recetas o providers que pone a nuestra disposición el frame. Trataré de explicarla en dos entradas, pero antes es necesario que recordemos cómo funciona el patrón singleton, pues, aunque ahora nos pueda parecer que no guarda relación alguna con el problema que nos interesa, luego entenderemos qué papel juega en este lío.

Si tenemos un objeto que hace el papel de clase y lo instanciamos, los valores originales del objeto clase siguen su vida tranquilos en la clase y en cada instancia siguen su propio camino.

var MiClase = function() {

this.foo = "Bazinga";

};

miInstanciaA = new MiClase();

miInstanciaA.foo = "Zasprist";

console.log(miInstanciaA.foo); // Zasprist

miInstanciaB = new MiClase();

miInstanciaB.foo = "Tachún";

console.log(miInstanciaA.foo); // Zasprist

console.log(miInstanciaB.foo); // Tachún

Esto puede ser muy útil cuando nos importa un pimiento el valor original de foo, pero no es el caso de las recetas de angular, donde es fundamental que siempre tengan el mismo valor. Es decir, que el valor foo de la receta miFactoria sea el mismo en el controlador uno que en el controlador dos. Y aquí es donde aparece el patrón singleton.

Este patrón de diseño tiene como objetivo que una clase solo tenga una instancia, de tal manera que solo tenga un punto de entrada. En javaScript, la manera más sencilla de crearlo es con un objeto literal:

/* Objeto literal */

var miObjeto = {

foo: "Bazinga",

bar: function() {

return "Zasprist";

}

};

console.log(miObjeto.foo); // Bazinga

miObjeto.foo = "oh oh";

console.log(miObjeto.foo); // oh oh

Si queremos un objeto más sofisticado, que tenga propiedades privadas, esto es, inaccesibles desde fuera del objeto, basta con poner las públicas en el return de una función autoejecutable y las demás declararlas con var. Como veremos, esto es parecido a lo que hacen las recetas del tipo factory.

/* Singleton con propiedades privadas */

var otroObjeto = (function() {

var propiedadInaccesible = "foo";

return {

propiedadAccesible: "Bazinga",

otra: "Bar"

}

})();

console.log(otroObjeto.propiedadAccesible); // Bazinga

console.log(otroObjeto.propiedadInaccesible); // undefined

Y también podemos diseñar un singleton en las funciones constructoras de tipo clase.

/* Singleton con función constructora */

var MiClase = (function() {

var instanciaCreada;

return function() {

/* Si existe instanciaCreada, la devolvemos (recordemos que en js no se lee nada después de un return) */

if ( instanciaCreada ) {

return instanciaCreada;

}

/* En caso contrario, le asignamos this */

instanciaCreada = this;

this.propiedadAccesible = "Bazinga";

this.metodoAccesible = function() {

// stuff

};

}

})();

foo = new MiClase();

console.log(foo.propiedadAccesible); // Bazinga

foo.propiedadAccesible = "Zasprist";

bar = new MiClase();

console.log(bar.propiedadAccesible); // Zasprist

Bueno, hay otras formas más o menos sofisticadas de definir un singleton, pero no vienen al caso, lo único importante es que entendamos qué es y para qué sirve. Vamos con las recetas.

Values y constantes

Una receta es un servicio que proporciona datos o funcionalidades a los controladores. En angular existen cinco tipos distintos de servicios (providers):

  1. values
  2. constants
  3. factories
  4. services
  5. providers

Los valores no son más que pares de clave / valor que podemos inyectar en los controladores refiriéndonos a la clave.

/* Values */

moduloPrincipal.value("foo", "Bazinga");

/* Controlador con recetas */

moduloPrincipal.controller('controladorRecetas', function($scope, foo) {

$scope.bar = foo; // Bazinga

});

Las constantes son muy parecidas, solo que su valor no se puede cambiar (ni siquiera con interceptores decorator, que ya veremos qué son otro día).

/* Constantes */

moduloPrincipal.constant("HERMANOS_MARX", {

"HERMANO_1": "Chico",

"HERMANO_2": "Harpo",

"HERMANO_3": "Groucho"

});

/* Controlador con recetas */

moduloPrincipal.controller('controladorRecetas', function($scope, foo, HERMANOS_MARX) {

$scope.bar = foo;

console.log(HERMANOS_MARX.HERMANO_3); // Groucho

});

Factories

Las factorías son las recetas (servicios) más utilizados y se usan sobre todo como almacén de datos o, mejor dicho, para recuperar y devolver datos, por lo general obtenidos de forma dinámica con llamadas ajax al server o similar. Su estructura básica es fácil de entender si tenemos en cuenta cómo funcionan los singleton:

/* Factory */

moduloPrincipal.factory("criaturas", function() {

var propiedadInaccesible = "golem";

var metodoInaccesible = function(criatura) {

return criatura.toUpperCase();

}

return [

{"criatura": metodoInaccesible("centauro")},

{"criatura": metodoInaccesible("troll")},

{"criatura": metodoInaccesible("sirena")}

];

});

moduloPrincipal.controller('controladorRecetas', function($scope, criaturas) {

$scope.todoCriaturas = criaturas;

console.log(criaturas.propiedadInaccesible); // undefined

});

Un ejemplo real de factoría sería una encargada de las llamadas REST.

angular.module('adminApp')

.factory('configData', function($http) {

var urlBase = "../rest/";

return {

getConfigBasic:function() {

return $http.get(urlBase+'config');

},

setConfigBasic: function(payload) {

if ( payload ) {

return $http.put(urlBase+'config', payload);

} else {

return false;

}

}

}

});

Services

Este tipo de recetas son muy parecidas a las factorías, pero a la hora de instanciarse equivalen a los objetos mediante función constructora, lo que tiene unas implicaciones muy sutiles que veremos más adelante.

/* Servicios */

moduloPrincipal.service('tiempo', function(){

this.devuelveAhora = function() {

var ahora = new Date();

var año = ahora.getFullYear();

var mes = ahora.getMonth();

var dia = ahora.getDate();

var hora = ahora.getHours();

var minutos = ahora.getMinutes();

var segundos = ahora.getSeconds();

return dia+" del "+mes+" de "+año+" a las "+hora+": "+minutos+": "+segundos;

};

this.devuelveTimestamp = function(ahora) {

return ahora.getTime();

};

});

moduloPrincipal.controller('controladorRecetas', function($scope, tiempo) {

console.log( "Este momento es: "+tiempo.devuelveAhora() );

console.log( "En timestampiano: "+tiempo.devuelveTimestamp( new Date() ) );

});

Bueno, de momento vamos a dejarlo aquí. En la próxima entrada veremos el quinto y más complicado tipo de receteas: los providers, que son generadores de factorías y servicios :P.

|| Tags: , ,

valoración de los lectores sobre angular y el cacao de las recetas I

  • estrellica valoración positiva
  • estrellica valoración positiva
  • estrellica valoración positiva
  • estrellica valoración positiva
  • estrellica valoración positiva
  • 4.5 sobre 5 (2 votos)

¿Te ha parecido útil o interesante esta entrada?
dormido, valoración 1 nadapensativo, valoración 2 un poco sonrisa, valoración 3 a medias guiño, valoración 4 bastante aplauso, valoración 5 mucho

Tú opinión es muy importante, gracias por compartirla!

Los comentarios están cerrados.