web-dev-qa-db-fra.com

Les modules chargés paresseusement peuvent-ils partager la même instance d'un service fourni par leur parent?

Je viens de rencontrer un problème avec un module paresseux où les modules parent et enfant nécessitent tous deux le même service mais créent chacun une instance. La déclaration est identique pour les deux, c'est-à-dire

import { MyService } from './my.service';
...
@NgModule({
   ...
   providers: [
      MyService,
      ...
   ]
});

et voici la configuration de routage

export parentRoutes: Routes = [
   { path: ':id', component: ParentComponent, children: [
      { path: '', component: ParentDetailsComponent },
      { path: 'child', loadChildren: 'app/child.module#ChildModule' },
      ...
   ]}
];

qui, bien sûr, est ensuite importé dans le module parent en tant que

RouterModule.forChild(parentRoutes)

Comment procéder si je souhaite partager la même instance de service?

31
Thorsten Westheider

L'utilisation d'un forRoot, comme mentionné ici , est probablement ce dont vous avez besoin. Le problème qu'il est censé résoudre est directement lié au problème que vous rencontrez avec les modules chargés paresseux obtenant leur propre service.

Il est expliqué ici dans Configurer les services principaux avec forRoot , mais cette section n'explique pas le problème du chargement paresseux. Cela s'explique par un petit avertissement à la fin de modules partagés

Ne spécifiez pas de singleton à l'échelle de l'application providers dans un module partagé. Un module chargé paresseusement qui importe ce module partagé fera sa propre copie du service.

@NgModule({})
class SharedModule {
  static forRoot() {
    ngModule: SharedModule,
    providers: [ MyService ]
  }
}

@NgModule({
  import: [ SharedModule.forRoot() ]
})
class AppModule {}

@NgModule({
  imports: [ SharedModule ]
})
class LazyLoadedModule {}

Cela garantit que le module chargé paresseusement n'obtient pas le service. Mais que le module soit ou non chargé paresseusement, c'est le modèle qui est recommandé pour les services à l'échelle de l'application. Bien qu'il soit à noter que si vous n'avez pas de module chargé paresseusement, n'utilisez pas le patter forRoot et importez simplement SharedModule, ce ne sera qu'une seule instance du service. Mais ce schéma devrait tout de même être recommandé.


MISE À JOUR

Je suppose que je suis allé trop vite pour répondre sans regarder complètement la question. Dans la question, il n'y a est aucune mention d'un module partagé. Il semble que l'OP essaie simplement d'ajouter le service au @NgModule.providers dans le module d'application et le module enfant chargé paresseux.

Dans ce cas, supprimez simplement le service du module enfant providers. Ce n'est pas nécessaire. Celui ajouté dans le module d'application suffit pour que l'enfant soit utilisé.

N'oubliez pas que providers est à l'échelle de l'application (sauf dans le cas problématique que ce message concerne), tandis que declarations ne l'est pas.

50
Paul Samsotha

Cela devrait fonctionner mais je vous suggère tout de même de choisir le concept SharedModule qui contient common les services, les tuyaux, les directives et les composants .

Shared/SharedModule

import { NgModule,ModuleWithProviders } from '@angular/core';
import { CommonModule }        from '@angular/common';

import { MyService } from './my.service';

@NgModule({
  imports:      [ CommonModule ],
  declarations: [],
  exports:      [ CommonModule ]
})
export class SharedModule {
  static forRoot(): ModuleWithProviders {
    return {
      ngModule: SharedModule,
      providers: [ MyService ]                       //<<<====here
    };
  }
}

AppModule

import {SharedModule} from './shared/shared.module';
...
@NgModule({
   imports:[ BrowserModule,SharedModule.forRoot()],  //<<<====here
   providers: []
});
16
micronyks