He leído que inyectar cuando el arranque debería hacer que todos los niños compartan la misma instancia, pero mis componentes principales y de encabezado (la aplicación principal incluye el componente de encabezado y la salida del enrutador) obtienen cada uno una instancia separada de mis servicios.
Tengo un FacebookService que uso para hacer llamadas a la API de JavaScript de Facebook y un UserService que usa FacebookService. Aquí está mi arranque:
bootstrap(MainAppComponent, [ROUTER_PROVIDERS, UserService, FacebookService]);Desde mi registro, parece que la llamada de arranque finaliza, luego veo que se crea FacebookService y luego UserService antes de que se ejecute el código en cada uno de los constructores, MainAppComponent, HeaderComponent y DefaultComponent:
La forma recomendada de crear un servicio singleton ha cambiado. Ahora se recomienda especificar en el decorador @Injectable en el servicio que debe proporcionarse en la 'raíz'. Esto tiene mucho sentido para mí y ya no es necesario enumerar todos los servicios proporcionados en sus módulos. Simplemente importa los servicios cuando los necesita y se registran en el lugar adecuado. También puede especificar un módulo para que solo se proporcione si se importa el módulo.
@Injectable({ providedIn: 'root', }) export class ApiService { }Con NgModule, creo que la forma de hacerlo ahora es crear un 'CoreModule' con su clase de servicio y enumerar el servicio en los proveedores del módulo. Luego, importa el módulo central en el módulo principal de su aplicación, que proporcionará una instancia a cualquier niño que solicite esa clase en sus constructores:
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ApiService } from './api.service'; @NgModule({ imports: [ CommonModule ], exports: [ // components that we want to make available ], declarations: [ // components for use in THIS module ], providers: [ // singleton services ApiService, ] }) export class CoreModule { } import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { AppComponent } from './app.component'; import { CoreModule } from './core/core.module'; @NgModule({ declarations: [ AppComponent ], imports: [ CommonModule, CoreModule // will provide ApiService ], providers: [], bootstrap: [ AppComponent ] }) export class AppModule { } Si enumera un proveedor en bootstrap() , no necesita enumerarlo en su decorador de componentes:
import { ApiService } from '../core/api-service'; @Component({ selector: 'main-app', templateUrl: '/views/main-app.html', // DO NOT LIST PROVIDERS HERE IF THEY ARE IN bootstrap()! // (unless you want a new instance) //providers: [ApiService] }) export class MainAppComponent { constructor(private api: ApiService) {} }De hecho, enumerar su clase en 'proveedores' crea una nueva instancia de la misma, si algún componente principal ya lo incluye, entonces los niños no necesitan hacerlo, y si lo hacen, obtendrán una nueva instancia.
¡Jason tiene toda la razón! Es causado por la forma en que funciona la inyección de dependencia. Se basa en inyectores jerárquicos.
Hay varios inyectores dentro de una aplicación Angular2:
Cuando Angular2 intenta inyectar algo en el constructor del componente:
Entonces, si desea tener un singleton para toda la aplicación, debe tener el proveedor definido a nivel del inyector raíz o del inyector del componente de la aplicación.
Pero Angular2 mirará el árbol del inyector desde abajo. Esto significa que se utilizará el proveedor del nivel más bajo y el alcance de la instancia asociada será este nivel.
Vea esta pregunta para más detalles:
Sé que angular tiene inyectores jerárquicos como dijo Thierry.
Pero tengo otra opción aquí en caso de que encuentre un caso de uso en el que realmente no quiera inyectarlo en el padre.
Podemos lograr eso creando una instancia del servicio, y al proporcionar siempre devolver eso.
import { provide, Injectable } from '@angular/core'; import { Http } from '@angular/core'; //Dummy example of dependencies @Injectable() export class YourService { private static instance: YourService = null; // Return the instance of the service public static getInstance(http: Http): YourService { if (YourService.instance === null) { YourService.instance = new YourService(http); } return YourService.instance; } constructor(private http: Http) {} } export const YOUR_SERVICE_PROVIDER = [ provide(YourService, { deps: [Http], useFactory: (http: Http): YourService => { return YourService.getInstance(http); } }) ];Y luego, en su componente, utiliza su método de suministro personalizado.
@Component({ providers: [YOUR_SERVICE_PROVIDER] })Y debería tener un servicio singleton sin depender de los inyectores jerárquicos.
No digo que esta sea una mejor manera, es solo en caso de que alguien tenga un problema donde los inyectores jerárquicos no son posibles.