web-dev-qa-db-fra.com

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

Quelqu'un peut-il m'éclairer, comment puis-je structurer plusieurs hiérarchies de modules de fonctions imbriquées avec des appels .forRoot ()?

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

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

Tous les modules de fonctionnalité ont des fonctions statiques .forRoot ().

Comment définir FeatureModuleA avec en quelque sorte "transférer" les fonctions .forRoot ()?

@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 la racine, puis la définir dans la fonction forRoot () de 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" des appels .forRoot () au sein de cette ModuleClass spéciale?

Comme je vois, je dois importer tous les sous-modules directement dans ma MainModule 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, veuillez consulter ce fichier: https://github.com/angular/material2/blob/master/src/lib/module.ts

Comme je connais ce référentiel mis à jour par l'équipe officielle angular. Ils résolvent donc ce qui précède simplement en important tous les appels .forRoot () dans un module spécial de MaterialRootModule. Je ne comprends pas vraiment être appliqué pour mon propre module racine? Qu'est-ce que la racine et . forRoot signifie-t-il vraiment? Est-ce relatif au package et non au projet Web proprement dit?

53
ggabor

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

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

Le raisonnement est que si vous ajoutez le AuthService au providers dans le @NgModule, il est possible que plusieurs d'entre eux soient créés si vous importez le SharedModule dans d'autres modules.

Je ne suis pas sûr à 100% de savoir si le service sera créé lorsque le SharedModule sera importé dans un module chargé avec impatience, mais l'explication mentionnée dans la documentation concernait les modules chargés paresseux. Lorsque vous chargez un module paresseusement, tous les fournisseurs seront créés.

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

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

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

Comme forRoot ne vise qu'à fournir des services singleton, vous pouvez les "redonner" explicitement dans 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 le SharedModule lui-même (pas par les sous-modules respectifs), mais il semble que cela n’a aucune importance. Peut-être que quelqu'un peut discuter si ...

Notez que FeatureModuleA peut également "fournir à nouveau" des services singleton à partir de ses sous-modules de la même manière.

5
Den Klimovsky

Comme mentionné ci-dessus, les modules chargés paresseux sont importants à considérer car un service partagé peut être utilisé dans un module chargé paresseux, mais si ce service a déjà été utilisé et instancié par un autre module, il y aura alors deux cas, d'où la nécessité du modèle singleton . Un AuthService est un bon exemple ici: vous ne voulez pas qu'une instance du service avec un utilisateur non authentifié soit authentifiée par une autre.

Nouveauté Angular 6): il existe un nouveau moyen d’enregistrer un fournisseur en tant que singleton. Dans le décorateur @Injectable () d’un service, utilisez l’attribut providedIn. Définissez sa valeur sur 'root'. Ensuite, vous n'aurez pas besoin de l'ajouter à la liste des fournisseurs du module racine, 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 {
...
1
thenninger