Saltar al contenido

Angular JS : Módulos y proveedores

AngularJS proporciona un modelo de inyección de fuerte dependencia para simplificar el desarrollo y las pruebas. Un aspecto clave de ese modelo es la noción de proveedores. Los proveedores son los bits de código que son responsables de instanciar o proporcionar instancias de las diversas dependencias utilizadas por su aplicación. Por ejemplo, para utilizar el servicio $http o el servicio $cookies en su aplicación, algún código tiene que proporcionar una instancia de esos servicios. Esa es la responsabilidad del $httpProvider y $cookiesProvider respectivamente que forman parte del marco AngularJS.

Los proveedores pueden crear muchos tipos de objetos, incluyendo tipos nativos de JavaScript como cadenas y fechas, así como tipos de objetos o servicios personalizados. La adición de controladores a un módulo es un ejemplo de un modelo de proveedor, ya que se debe proporcionar una función para definir el controlador. Para otros tipos de objetos, funciones y valores utilizados en una aplicación, se pueden escribir proveedores personalizados.

Angular JS : Módulos y proveedores
Angular JS : Módulos y proveedores

Existe un patrón básico para crear un proveedor que proporcione la mayor flexibilidad pero que también requiera la mayor cantidad de trabajo. Usando este modelo se define una función y se incluye una propiedad $get que será invocada por AngularJS para crear su objeto. Es importante tener en cuenta que todos los proveedores crean singletons, por lo que sólo se les pedirá que proporcionen el objeto una vez. Después de eso, el objeto es almacenado en el servicio de inyectores de AngularJS donde puede ser buscado cuando sea necesario para cumplir con una declaración de dependencia.

1234567891011functioncalendarProvider(){var cal ="es.usa";this.setCalendar=function(calendar){ cal = calendar;};this.$get=[$0027calendarToken$0027,function(calendarToken){returnnewLocalCalendarService(cal);}];}angular.module("mainModule").provider("calendar", calendarProvider)

javascript

En esta implementación del proveedor, el objeto tiene un método, setCalendar, que puede ser usado para configurar el proveedor. Este tipo de configuración permite al proveedor ser más flexible y útil en diferentes aplicaciones o entornos. La propiedad $get es el núcleo de la implementación del proveedor. Fíjese que soporta la inyección de dependencias de otros proveedores con una lista de dependencias y luego tiene una función responsable de la creación del objeto que se está proporcionando. Esta función puede utilizar las dependencias como se muestra, así como variables locales en el proveedor, como la variable «cal» mostrada, que permite la configuración.

En este ejemplo, la función devuelve un objeto personalizado pero también podría devolver una cadena, fecha, función u otro tipo simple. En las dos últimas líneas de código el proveedor se añade a un módulo. Recuerde que los módulos son los contenedores de todos los aspectos del código en una aplicación AngularJS y contienen no sólo los controladores, directivas y filtros, sino también los propios proveedores.

Para utilizar el objeto proporcionado, un controlador u otro tipo de dependencia habilitado puede declarar una dependencia en el nombre registrado del proveedor, como se muestra en este ejemplo con un controlador.

12angular.module($0027mainModule$0027).controller($0027mainController$0027,[$0027calendarService$0027,$0027calendar$0027, mainController]);

javascript

Como ya se ha mencionado, esta es la pauta básica de un proveedor y conlleva ciertos beneficios, como el apoyo a las dependencias y la posibilidad de ser configurado. Hablaré más sobre la configuración en breve, lo que ayudará a determinar si ese beneficio es necesario en una aplicación. Sin embargo, para muchas situaciones, esto es más trabajo que debería ser requerido para crear un objeto. Por esa razón, AngularJS provee varios métodos en un módulo que proveen atajos para crear ciertos tipos de objetos. Cada uno de estos métodos es una simple envoltura sobre un proveedor real creado entre bastidores, y cada uno tiene características y rasgos ligeramente diferentes.

Proveedor de servicios

El proveedor de servicios permite la creación de un objeto personalizado utilizando el patrón constructor. En otras palabras, si tiene un objeto que puede ser creado usando la palabra clave «nuevo», con o sin parámetros, entonces puede usar un atajo para crear ese servicio. Por ejemplo, el siguiente objeto de servicio recupera los días festivos de un calendario de Google e invoca una llamada con los resultados. El servicio tiene dependencias como se indica en los parámetros de la función de construcción.

123456789101112functionCalendarService(calendarUrlFactory, $http){this.getHolidays=function(cb){ $http.get(calendarUrlFactory).then(function(results){cb(results,null);},function(error){cb(null, error);};}}

javascript

En lugar de crear una implementación completa del proveedor para este objeto, se puede invocar el método de servicio de atajo en el módulo.

1234angular.module("mainModule").service($0027calendarService$0027,[$0027calendarUrlFactory$0027,$0027$http$0027,function(calendarUrlFactory, $http){returnnewCalendarService(calendarUrlFactory, $http);}]);

javascript

El método de servicio toma un nombre para el servicio, una lista de dependencias y una simple función para crear el objeto. Este código sustituye al código de proveedor mostrado anteriormente para crear el objeto. El uso de este patrón sigue proporcionando soporte para la inyección de dependencias en el servicio, como se muestra en el ejemplo en el que se enumeran las dependencias del servicio calendarUrlFactory y $http. Sin embargo, una desventaja de este modelo más simple es que no permite la configuración del proveedor antes de que se cree el servicio.

Una vez que este proveedor de servicios se ha registrado en el módulo, puede ser declarado como una dependencia en otros módulos y sus componentes.

Proveedor de la fábrica

En algunos casos, el objeto devuelto por un proveedor no es un objeto personalizado sino un tipo nativo como una cadena, un número o una función. En esos casos se puede utilizar un proveedor de fábrica para crear el objeto. Este proveedor es muy parecido al proveedor de servicios pero no devuelve un objeto personalizado.

1234angular.module("mainModule").factory("calendarUrlFactory",[$0027calendarName$0027,$0027calendarToken$0027,function(calendarName, calendarToken){return calendarName +"/events? maxResults=10&key="+ calendarToken;}]);

javascript

En este ejemplo se invoca el método de la fábrica en el módulo para registrar una función para crear un URL de calendario computarizado. La función tiene dos dependencias que se utilizan para calcular el valor en tiempo de ejecución. Este tipo de proveedor permite el mismo atajo sobre el modelo de proveedor más verborreico e incluye soporte para las dependencias. La principal diferencia entre este proveedor y el proveedor de servicios está en los tipos que se devuelven. Puede ver un ejemplo de esta fábrica que se utiliza una dependencia en el ejemplo anterior en el que el servicio la utiliza internamente para realizar algún trabajo.

Proveedor de valor

En algunos casos puede ser necesario simplemente proporcionar un valor a lo largo de una aplicación desde una ubicación de código centralizada. En esos casos, el proveedor de valores hace que sea sencillo registrar un valor con el inyector que luego puede utilizarse en toda la aplicación.

12angular.module("mainModule").value("calendarName", "https://www.googleapis.com/calendar/v3/calendars/. . .");

javascript

Aquí el método de valores del módulo registra una simple cadena con el inyector. En otra parte de la aplicación se puede declarar una dependencia en el proveedor «calendarName». El objeto proporcionado para ese nombre será el valor que se registró con este método. El ejemplo anterior de un proveedor de fábrica utilizaba una dependencia de este proveedor para obtener el valor del nombre de calendario con el fin de crear la URL completa. El uso de este sencillo tipo de proveedor permite colocar los valores importantes para la aplicación en una sola ubicación del código. Ya no hay más cadenas mágicas esparcidas en ese código ni necesidad de un servicio que envuelva los valores de configuración.

Una distinción importante entre este tipo de proveedor y otros es que el proveedor de valor no apoya las dependencias. Se espera que un proveedor de valor devuelva un objeto por sí mismo sin el apoyo de otros servicios, por lo que es más útil para tipos y funciones primitivas.

Proveedor constante

La última forma de crear un proveedor es el método constante en el módulo para definir un valor constante como se muestra aquí.

12angular.module($0027mainModule$0027).constant("calendarToken", "YOUR API TOKEN ");

javascript

Al igual que el proveedor de valor, este proveedor registra un valor simple con el inyector para que esté disponible en todo el código. La pregunta natural es por qué este proveedor es necesario en absoluto y qué características es el apoyo que el proveedor de valor no. La respuesta corta es que, a diferencia del proveedor de valor, el proveedor constante está disponible en el momento de la configuración. La respuesta más larga requiere una discusión sobre la configuración del proveedor y el proceso de tiempo de ejecución de la carga de los proveedores y servicios.

Ciclo de vida del proveedor y del servicio

Cuando el proceso de arranque se ejecuta, una aplicación AngularJS pasa por dos etapas: configuración y ejecución. Durante el proceso de configuración cada proveedor es instanciado, luego cada módulo es configurado llamando al método de configuración si existe. Es en el método de configuración donde los proveedores que siguen el modelo de proveedor completo pueden tener funciones invocadas para configurarlos.

1234angular.module($0027mainModule$0027,[$0027secondModule$0027]).config([$0027calendarProvider$0027,function(calendarProvider){ calendarProvider.setCalendar("en.usa");}]);

javascript

El método de configuración del módulo acepta una lista de dependencias como la de los servicios, pero en este caso la lista es de proveedores que luego se pasan a la función. Todo esto ocurre antes de que los módulos se ejecuten y, por lo tanto, los servicios no están disponibles durante esta fase porque aún no se han creado. Observe que ninguno de los otros tipos de proveedores pueden ser configurados en este momento.

Sin embargo, durante la fase de configuración los proveedores constantes están disponibles para su uso. Esto significa que las funciones o valores registrados a través de los proveedores constantes pueden utilizarse para configurar los demás proveedores, así como para ser utilizados en tiempo de ejecución por los servicios, controladores, etc. Por ejemplo, suponiendo que el proveedor de calendario se actualizara para incluir un método setToken, se puede utilizar el siguiente código de configuración.

12345angular.module($0027mainModule$0027,[$0027secondModule$0027]).config([$0027calendarProvider$0027,$0027calendarToken$0027,function(calendarProvider, calendarToken){ calendarProvider.setCalendar("es.usa"); calendarProvider.setToken(calendarToken);}]);

javascript

La función de configuración tiene ahora una dependencia del proveedor de constantes de calendarToken que permite que se use para pasar el token al proveedor de calendarToken al momento de la configuración. Este es el gran beneficio del proveedor constante: ser accesible en el momento de la configuración y en el tiempo de ejecución.