Estoy jugando con los Módulos en Angular. Y como siempre, me gusta hacer un ejemplo lo más sencillo posible para asentar los conceptos. Mi ejemplo: un módulo principal «tonto» que importe un módulo «Greeting» y lo use.
Como los módulos teóricamente sirven para agrupar componentes y exponer solo algunas de ellas, pues a «Greeting» le pongo un servicio GreetingService que devuelva un «Hola» y un componente GreetingComponent que lo muestre en pantalla. La idea es exportar el componente ocultando el servicio al módulo principal.
Sin problemas por el lado del componente. En el fichero greeting.module.ts basta poner en declarations y en exports el componente GreetingComponent.
@NgModule({
declarations: [GreetingComponent],
exports: [GreetingComponent],
...
})
export class GreetingModule { }
Pero con los servicios… ¡Menudo lío!. Entenderlo me ha dado bastante guerra. Estaba empeñado en ocultar el servicio salvo que el módulo lo exportara, pero no es posible. Los servicios no tienen nada que ver con los módulos. Más allá de que un módulo diga que necesita un servicio.
Cuando declaramos un servicio, podemos ponerle providedIn y decirle dónde se registra. Hay cinco valores posibles: Un nombre de módulo o componente. Uno de los textos ‘root’, ‘platform’ o ‘any’. O bien null o dejarlo vacío, que es lo mismo. Pero tienen comportamientos muy similares y dos de esas opciones están obsoletas. ‘platform’ es un caso especial que sólo tiene sentido si varias aplicaciones Angular corren en el mismo navegador. Así que quedan
- ‘root‘: Se instancia el servicio una sola vez cuando alguien lo necesite y está diponible para todo el que lo quiera, sin necesidad de que lo declare en su apartado ‘providers’
- null: Se instancia el servicio una vez cuando alguien lo necesite, pero tienen que ponerlo en su apartado ‘providers’
Así que providedIn sirve básicamente para decir si el servicio está diponible por defecto para todo el mundo o sólo para el que lo indique explícitamente en ‘providers’.
Pero hay más. Había varias opciones que están obsoletas y todas hablan de que pueda haber varias instancias del mismo servicio. ¿Es esto posible? ¿Y cómo funciona?
Con la opción ‘root’ no hay nada de esto. Instancia única para todos.
Pero la opción null sí permite esto. El mecanismo es el siguiente. Cuando se carga la aplicación para ponerla en marcha, habrá una serie de módulos angular de nuestra aplicación (los decorados con ‘@NgModule’) que se cargarán en el arranque porque la página que se muestra inicialmente los necesita.
Pero podemos crear módulos que no se necesiten en el arraque y luego, por alguna acción del usuario como pinchar un enlace o un botón, provocar la carga del módulo para mostrarle un determinado contenido nuevo. Estos modulos los llamaremos ‘lazy loaded modules’.
Y una vez soltado este rollo, ¿qué hace la opción null de providedIn?. Todos los módulos que se cargan en el arranque compartirán una misma instancia del servicio. Pero los módulos ‘lazy loaded’ obtendrán instancias nuevas de este servicio.
Resumen:
Aparte de ‘platform’, sólo hay dos opciones no obsoletas para providedIn.
‘root’ : Una instancia única del servicio para todo el que la necesite y el que la necesite no tiene que ponerla en ‘providers’. Es la forma aconsejada.
null: Una instancia única para todos los módulos que se carguen en el arranque de la aplicación. Una instancia nueva para los módulos ‘lazy loaded’ que se carguen después. El que necesite este servicio tiene que ponerlo en ‘providers’. Debería usarse sólo en caso de que el servicio tenga un estado interno propio para cada posible cliente. Y en este caso, todos los módulos, salvo quizás uno, deberían ser ‘lazy loadaded’ para asegurar que cada módulo tiene su propia instancia.