> Manuales > Manual de AngularJS

Qué son las factorías de AngularJS, factory en la terminología Angular. Para qué sirven, qué rasgos las caracterizan y cómo crearlas.

Hasta el momento en el Manual de AngularJS nuestro código Javascript lo hemos colocado principalmente dentro de controladores. Nos han servido perfectamente para nuestras aplicaciones, pero ya hemos podido observar que en ciertas ocasiones los controladores no se comportan como nosotros podríamos desear.

Aspectos de esta problemática han debido de quedar claros si te lees con calma el último artículo, donde aprendimos a crear controladores en paralelo y donde introdujimos $location. En ese ejercicio vimos que los controladores se invocan con cada vista donde los estemos usando, ejecutando la función que los define cada vez que se carga la vista. Por ese motivo todos los datos que se se inicializan en los controladores se vuelven a poner a sus valores predeterminados cuando cargo cualquier vista que trabaje con ese controlador.

Terminamos el artículo pasado mencionando que las factorías nos podrían solucionar la pérdida de datos de los controladores cuando cambiamos la vista. De modo que vamos a aprender a crearlas y utilizarlas.

Pero ese no es el único caso donde encontrarás utilidad en las factorías. Por ejemplo, algunas de las necesidades que podríamos tener y que los controladores no nos resuelven son:

1) Compartir datos entre varios controladores, lo que permite tener aplicaciones de verdad, capaces de memorizar estados entre varias de sus pantallas.

2) Compartir datos entre varias vistas distintas. Por supuesto, sin usar las temidas variables globales. Eso es justamente lo que vimos en el artículo anterior, que ya tengas uno o varios controladores, no comparten ni se memorizan estados al pasar de una vista a otra.

Además, quizás el más representativo de los usos de las factorías es:

3) Empaquetar operaciones comunes a varios controladores (por ejemplo en una aplicación de facturación podríamos necesitar calcular el IVA o acceder a los distintos tipos de IVA en varios puntos del sistema). Por supuesto, no queremos colocar el código de esos cálculos u operaciones repetido en todos los controladores que deben utilizarlos y tampoco deseamos crear funciones con ámbito global.

Qué son las factorías

Las factorías son como contenedores de código que podemos usar en nuestros sitios desarrollados con AngularJS. Son un tipo de servicio, "service" en Angular, con el que podemos implementar librerías de funciones o almacenar datos.

Cuando las usamos tienen la particularidad de devolvernos un dato, de cualquier tipo. Lo común es que nos devuelvan un objeto de Javascript donde podremos encontrar datos (propiedades) y operaciones (métodos). Con diferencia de los controladores, las factorías tienen la característica de ser instanciados una única vez dentro de las aplicaciones, por lo que no pierden su estado. Por tanto, son un buen candidato para almacenar datos en nuestra aplicación que queramos usar a lo largo de varios controladores, sin que se inicialicen de nuevo cuando se cambia de vista.

Angular consigue ese comportamiento usando el patrón "Singleton" que básicamente quiere decir que, cada vez que se necesite un objeto de ese tipo, se enviará la misma instancia de ese objeto en lugar de volver a instanciar un ejemplar.

Nota: El patrón "Singleton" no es algo específico de AngularJS, en realidad es un patrón general de programación orientada a objetos. Así como las factorías en líneas generales también son un conocido patrón de diseño de software que se usa en el desarrollo de aplicaciones web y aplicaciones tradicionales orientadas a objetos.

Notas sobre los "services" en Angular

Los "services" en AngularJS incluyen tanto factorías como servicios. Más adelante veremos la diferencia. Lo que queremos mencionar ahora es que estos contenedores de código ya los hemos usado en diversas ocasiones y quizás podrás entender su utilidad mejor si analizamos cosas que ya conoces.

Por ejemplo, cuando estás haciendo Ajax, por los métodos que hemos conocido hasta el momento, usamos $http. Éste no es más que un service de Angular que engloba toda la funcionalidad necesaria para realizar solicitudes asíncronas a un servidor.

Por tanto, algo como Ajax, que se supone que puedes querer realizar a lo largo de tu aplicación en varias partes del código, se ha separado a un "servicio". Esto quiere decir que, cuando quieras hacer Ajax, tendrás que usar el código del "service" $http.

Los servicios y factorías que desees usar en tus controladores o módulos deberás inyectarlos como has visto hacer en diversas partes de nuestros ejemplos. No te preocupes si no lo recuerdas porque a continuación veremos ejemplos.

Ejemplo de factoría en AngularJS

Ahora nos vamos a poner manos a la obra creando nuestra primera factoría. Para ello vamos a continuar con el ejercicio que hemos visto en los artículos anteriores del Manual de AngularJS. Como recordarás, queremos implementar un sistema que nos memorice cierta información de nuestra aplicación a lo largo de diversas vistas.

Implementamos factorías con el método factory() que depende del módulo (objeto module) de nuestra aplicación.

Osea, como cualquier aplicación de Angular, lo primero crearás tu "module" principal:

angular.module("app", ["ngRoute"])

Y sobre el objeto que devuelve esa operación crearemos las factorías.

Nota: Como observarás, el mecanismo para crear la factoría es el mismo que hacemos para crear los controladores. Para crear el controlador usas el método controller() y para la factoría el método factory().

.factory("descargasFactory", function(){
    var descargasRealizadas = ["Manual de Javascript", "Manual de jQuery", "Manual de AngularJS"];

    var interfaz = {
        nombre: "Manolo",
        getDescargas: function(){
            return descargasRealizadas;
        },
        nuevaDescarga: function(descarga){
            descargasRealizadas.push(descarga);
        }
    }
    return interfaz;
})

Esta factoría se llama "descargasFactory". El nombre lo hemos definido en la llamada al método factory. Acuérdate de este nombre, pues luego lo tendrás que usar al inyectar la dependencia de esta factoría en tus controladores.

Ese código tiene una serie de detalles interesantes, desde el punto de vista de Angular y también desde el de Javascript en general. Estudiar el código anterior con detalle es suficiente para un único artículo, porque entran en juego diversos conceptos de la programación orientada a objetos en Javascript. De todos modos, te vamos a resumir un poco lo que encuentras.

Nota: Para entender las ventajas hacer las cosas públicas o privadas deberás conocer algunos de los conceptos básicos de programación en general y programación orientada a objetos en particular, como son la abstracción y el encapsulamiento. Es una decisión de diseño de software, que debe tomar el desarrollador y tanto Javascript como por extensión AngularJS tienen mecanismos para implementar elementos públicos o privados. Así, como regla global en la programación orienta a objetos, todo dato debería ser definido como privado, a no ser que alguien de fuera te solicite que lo expongas públicamente.

Usar una factoría

Ahora podemos ver cómo usar la factoría que acabamos de realizar. El procedimiento es tan simple como, una vez definida, inyectarla en el controlador donde la queremos usar. Usamos el sistema de inyección de dependencias que ya conoces.

Al crear la función del controlador debemos definir un parámetro que se llame exactamente igual al nombre que le has dado en la factoría. En este caso el parámetro que inyectamos en el controlador se llama "descargasFactory" pues así habíamos llamado a la factoría al crearla.

Echa ahora un vistazo a un controlador que usa esta factoría.

.controller("appCtrl", function(descargasFactory){
    var vm = this;
    
    vm.nombre = descargasFactory.nombre;
    vm.descargas = descargasFactory.getDescargas();
    vm.funciones = {
        guardarNombre: function(){
            descargasFactory.nombre = vm.nombre;
        },
        agregarDescarga: function(){
            descargasFactory.nuevaDescarga(vm.nombreNuevaDescarga);
            vm.mensaje = "Descarga agregada";
        },
        borrarMensaje: function(){
            vm.mensaje = "";
        }
    }
});

Dentro de nuestro controlador la variable descargasFactory que recibimos como parámetro contiene todos los datos y funciones que hemos definido en la interfaz pública de nuestra factoría.

Por tanto:

- descargasFactory.nombre contendrá la propiedad "nombre" definida en la factory.
- descargasFactory.nuevaDescarga() o descargasFactory.getDescargas() serán llamadas a los métodos que habíamos definido en la factoría.

Nota: Ojo, desde tu vista, en el HTML, no serás capaz de acceder a la factoría. Es algo que ahora pertenece al controlador y a través del scope creado por ese controlador no puedes acceder a los datos que tienen sus dependencias. Si quieres acceder a un dato de esa factoría el mecanismo es volcar ese dato en el scope. Eso lo hacemos al principio de ese controlador en las líneas:

vm.nombre = descargasFactory.nombre;
vm.descargas = descargasFactory.getDescargas();

Creo que con todo esto queda explicado el trabajo con las factorías en AngularJS. Ahora faltaría un poco de tiempo por tu parte para poder ponerlo en práctica.

Alberto Basalo

Alberto Basalo es experto en Angular y otras tecnologías basadas en Javascript,...

Manual