63 votes

Comment utiliser la fonction .forRoot() dans la hiérarchie des modules de fonctionnalités ?

Quelqu'un peut-il m'expliquer comment structurer la hiérarchie de plusieurs modules de fonctionnalités imbriqués avec les éléments suivants .forRoot() des appels ?

Par exemple, si j'ai des modules comme celui-ci :

- MainModule
- SharedModule
- FeatureModuleA
    - FeatureModuleA1
    - FeatureModuleA2
- FeatureModuleB

Tous les modules de fonctionnalités ont un .forRoot() fonction statique.

Comment dois-je définir FeatureModuleA avec en quelque sorte "transférer" le .forRoot() fonctions ?

@NgModule({ 
  imports: [
    //- I can use .forRoot() calls here but this module not the root module
    //- I don't need to import sub-modules here, FeatureA only a wrapper
    //FeatureModuleA1.forRoot(), //WRONG!
    //FeatureModuleA2.forRoot(), //WRONG!
  ],
  exports: [
    //I cannot use .forRoot() calls here
    FeatureModuleA1, 
    FeatureModuleA2 
  ]
})
class FeatureModuleA {
  static forRoot(): ModuleWithProviders {
    return {
      //At this point I can set any other class than FeatureModuleA for root
      //So lets create a FeatureRootModuleA class: see below!
      ngModule: FeatureModuleA //should be: FeatureRootModuleA 
    };
  }
}

Je peux créer une autre classe pour l'utilisation de Root, puis la définir dans l'application forRoot() fonction du FeatureModuleA :

@NgModule({
  imports: [
    //Still don't need any sub module within this feature module
  ]
  exports: [
    //Still cannot use .forRoot() calls but still need to export them for root module too:
    FeatureModuleA1, 
    FeatureModuleA2 
  ]
})
class FeatureRootModuleA { }

Mais comment puis-je "transférer" .forRoot() dans cette classe de module spéciale ?

Comme je le vois, je dois importer tous les sous-modules directement dans mon module principal racine et appeler .forRoot() pour chacun d'entre eux :

@NgModule({
  imports: [
    FeatureModuleA1.forRoot(),
    FeatureModuleA2.forRoot(),
    FeatureModuleA.forRoot(),
    SharedModule.forRoot()
  ]
})
class MainModule { }

Ai-je raison ? Avant de répondre, jetez un coup d'œil à ce dossier : https://github.com/angular/material2/blob/master/src/lib/module.ts

Comme je le sais, ce dépôt est maintenu par l'équipe officielle d'Angular. Ils ont donc résolu le problème ci-dessus en important simplement tous les fichiers de l'application .forRoot() dans un module spécial MaterialRootModule. Je ne comprends pas vraiment comment cela pourrait être appliqué à mon propre module Root ? Que fait le Raíz y .forRoot veut vraiment dire ici ? Est-ce que c'est relatif au paquet et non au projet web réel ?

0 votes

Je ne suis pas sûr de la raison pour laquelle vous voulez créer et utiliser une forRoot méthode peut-être que ça aide : angular.io/docs/ts/latest/guide/ngmodule.html

1 votes

Oui. J'ai lu la documentation officielle. Il n'y a rien sur la façon de structurer des projets complexes avec plusieurs modules imbriqués. Je veux créer et utiliser forRoot exactement parce que les singletons des fournisseurs ne doivent être installés qu'une seule fois dans tout le projet.

0 votes

Ok, parce qu'il n'y avait pas de fournisseurs dans votre exemple :)

109voto

peeskillet Points 32287

Généralement forRoot est utilisé pour ajouter des services d'application/singlet.

@NgModule({
  providers: [ /* DONT ADD HERE */ ]
})
class SharedModule {
  static forRoot() {
    return {
      ngModule: SharedModule,
      providers: [ AuthService ]
    }
  }
}

Le raisonnement est que si vous ajoutez le AuthService à la providers dans le @NgModule il est possible d'en créer plus d'un si vous importez l'image de marque de l'entreprise. SharedModule dans d'autres modules.

Je ne sais pas exactement si le service doit être créé lorsque l'agent de sécurité de l'entreprise est activé. SharedModule est importé dans un module à chargement rapide, mais l'explication mentionnée dans la documentation concernait les modules à chargement lent. Lorsque vous chargez paresseusement un module, tous les fournisseurs sont créés.

Pour cette raison, nous ajoutons (par convention) un forRoot pour signifier que la méthode ne doit être appelée que pour le module Root (app), tandis que pour les autres modules, elle doit être importée normalement.

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

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

0 votes

Merci pour vos efforts mais cela ne tient toujours pas compte du cas des modules imbriqués à plusieurs niveaux. Dans votre exemple, vous avez importé AuthService dans le SharedModule. Pouvez-vous s'il vous plaît remanier votre exemple en important SharedModule (module, au lieu de service !) - et essayer d'utiliser AuthModule.forRoot() quelque part. (disclaimer : pour moi l'AuthService/AuthModule est juste un exemple ici - il peut s'agir de n'importe quel module avec les méthodes forChild et forRoot).

4 votes

ForRoot ne doit être utilisé que pour le module d'application. Il ne devrait pas être nécessaire de faire suivre quoi que ce soit. Lorsque vous importez Just SharedModule sans forRoot, forRoot n'est jamais appelé. Nous devrions structurer nos modules de cette façon. Les services de l'application sont dans forRoot, et tout le reste dans le module NgModule. Emboîté ou non, voici comment vous devriez le considérer

0 votes

Si vous avez besoin d'importer le module de fonctionnalité dans d'autres modules de fonctionnalité, allez-y, ça ne fait pas de mal. Souvenez-vous simplement de la règle empirique concernant les fournisseurs à l'échelle de l'application dans le forRoot et tout devrait bien se passer

10voto

Den Klimovsky Points 31

Comme forRoot destinés uniquement à fournir des services singletons, vous pouvez les "re-fournir" explicitement dans le fichier SharedModule :

@NgModule({})
class SharedModule {
  static forRoot() {
    return {
      ngModule: SharedModule,
      providers: [
        AuthService,
        FeatureModuleA.forRoot().providers,
        FeatureModuleB.forRoot().providers,
      ],
    }
  }
}

De cette façon, tous les services seront fournis par la SharedModule (pas par le sous-module respectif) mais il semble que cela n'ait pas d'importance. Peut-être que quelqu'un peut argumenter cependant...

Notez, que FeatureModuleA peut également "re-fournir" des services singletons à partir de ses sous-modules de manière similaire.

0 votes

Ce qui manque dans la plupart des réponses est - comment utiliser AuthService dans d'autres modules - si je ne mets pas AuthService dans les fournisseurs, il échoue. Si je le place dans les providers, il ne le traite pas comme un singleton.

0 votes

Vous devez ajouter SharedModule.forRoot() aux "imports" de votre AppModule. De cette façon, Angular fournira tous ces services pour l'injecteur de racine (AppModule), d'où les singletons.

1voto

thenninger Points 421

Comme mentionné ci-dessus, les modules chargés paresseusement sont importants à prendre en compte car un service partagé peut être utilisé dans un module chargé paresseusement, mais si ce service a déjà été utilisé et instancié par un autre module, il y aura deux instances, d'où la nécessité du modèle singleton. Un AuthService est un excellent exemple ici - vous ne voulez pas avoir une instance du service avec un utilisateur non authentifié alors qu'une autre a "le même" utilisateur authentifié.

Dans Angular 6, il existe une nouvelle façon d'enregistrer un fournisseur en tant que singleton. À l'intérieur du décorateur @Injectable() d'un service, utilisez l'attribut providedIn. Définissez sa valeur sur "Root". Ainsi, vous n'aurez pas besoin de l'ajouter à la liste des fournisseurs du module Root, ou dans ce cas, vous pouvez également le définir sur votre SharedModule comme ceci :

@Injectable({
  providedIn: SharedModule // or 'root' for singleton
})
export class AuthService {
...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X