Fermer

mai 2, 2018

Utilisation de NgModules angulaires pour le code réutilisable et plus –


Les NgModules sont un concept de base dans Angular qui fait partie de chaque application et qui aide à connecter certains détails importants pour le compilateur et l'exécution de l'application. Ils sont particulièrement utiles pour organiser le code en fonctionnalités, itinéraires de chargement paresseux, et créer des bibliothèques réutilisables.

Dans ce guide, nous allons couvrir les utilisations principales de NgModules avec quelques exemples pour vous montrer comment les utiliser dans votre Projets angulaires! Ce guide suppose que vous avez une connaissance pratique d'Angular

Les modules JavaScript ne sont pas des NgModules

Essayons d'abord de clarifier ce que sont les modules JavaScript (parfois appelés modules ES6). Ils sont une structure de langage qui facilite l'organisation de votre code.

À leur base, les modules Javascript sont des fichiers JavaScript qui contiennent l'exportation import ou mots-clés, et qui font que les objets définis à l'intérieur de ce fichier sont privés sauf si vous l'exportez. Je vous encourage à consulter le lien ci-dessus pour une compréhension plus approfondie, mais essentiellement c'est un moyen d'organiser votre code et de le partager facilement, sans compter sur la portée mondiale redoutée.

Lorsque vous créez une application Angular avec TypeScript, vous utilisez import ou export dans votre source, il est traité comme un module JavaScript. TypeScript est capable de gérer le chargement du module pour vous.

Note: pour aider à clarifier les choses dans cet article, je ferai toujours référence aux modules JavaScript et NgModules par leurs noms complets.

The Basic NgModule, AppModule

Commençons par regarder un NgModule de base qui existe dans chaque application Angular, le AppModule (qui est généré par défaut dans toute nouvelle application Angular). Cela ressemble à quelque chose que vous voyez ici:

 import {BrowserModule} à partir de '@ angular / platform-browser';
importer {NgModule} à partir de '@ angular / core';

importez {AppComponent} à partir de './app.component';

@NgModule ({
  déclarations: [
    AppComponent
  ],
  importations: [
    BrowserModule
  ],
  fournisseurs: [],
  bootstrap: [AppComponent]
})
classe d'exportation AppModule {}

Angular utilise des décorateurs pour définir les métadonnées dont il a besoin de connaître pendant la compilation. Pour définir un NgModue, il suffit d'ajouter le décorateur @NgModule () au-dessus d'une classe. La classe n'est pas toujours vide, mais c'est souvent le cas. Cependant, vous devrez définir un objet avec des propriétés pour que le module NgModule puisse faire quoi que ce soit.

Lorsque l'application s'amorce, il faut lui donner un NgModule à instancier. Si vous regardez dans le fichier principal de votre application (généralement appelé main.ts ), vous verrez platformBrowserDynamic (). BootstrapModule (AppModule) qui est la manière dont l'application enregistre et initie le AppModule (qui peut être nommé n'importe quoi, mais presque toujours nommé ainsi)

Les propriétés de NgModule

La page de documentation NgModule API décrit les propriétés vous pouvez passer lors de la définition d'un NgModule, mais nous allons les couvrir ici aussi. Ils sont tous facultatifs, mais vous devrez définir des valeurs pour au moins un d'entre eux pour que le module NgModule fasse quoi que ce soit.

providers

Les providers sont un tableau qui contient la liste des tout fournisseurs (services injectables) disponibles pour ce NgModule. Les fournisseurs ont une portée, et s'ils sont listés dans un NgModule paresseux, ils ne sont pas disponibles en dehors de ce NgModule.

déclarations

Le tableau déclarations devrait contenir une liste de toutes des directives, des composants ou des canaux que ce NgModule définit. Cela permet au compilateur de trouver ces éléments et de s'assurer qu'ils sont correctement regroupés. Si c'est la racine NgModule, alors les déclarations sont disponibles pour tous les NgModules. Sinon, ils ne sont visibles que par le même NgModule.

imports

Si votre NgModule dépend d'autres objets d'un autre NgModule, vous devrez l'ajouter au tableau imports . Cela garantit que le compilateur et le système d'injection de dépendances connaissent les éléments importés.

exports

En utilisant le tableau exports vous pouvez définir les directives, composants et canaux disponibles pour tout module NgModule importé. ce NgModule. Par exemple, dans une bibliothèque d'interface utilisateur, vous exportez tous les composants qui composent la bibliothèque.

entryComponents

Tout composant devant être chargé au moment de l'exécution doit être ajouté à la liste de entryComponents ] Essentiellement, cela créera la fabrique de composants et la stockera pour quand elle doit être chargée dynamiquement. Vous pouvez en apprendre plus sur la façon de charger dynamiquement des composants à partir de la documentation

bootstrap

Vous pouvez définir n'importe quel nombre de composants à amorcer lors du premier chargement de l'application. Habituellement, vous n'avez besoin que d'amorcer le composant racine principal (généralement appelé AppComponent ), mais si vous avez plus d'un composant racine, chacun sera déclaré ici. En ajoutant un composant au tableau bootstrap il est également ajouté à la liste des entryComponents et précompilés.

schémas

Les schémas sont un moyen de définir comment Angular compile les templates, et s'il va lancer une erreur lorsqu'il trouve des éléments qui ne sont pas du HTML standard ou des composants connus. Par défaut, Angular renvoie une erreur lorsqu'il trouve un élément dans un modèle qu'il ne connaît pas, mais vous pouvez modifier ce comportement en définissant le schéma sur NO_ERRORS_SCHEMA (pour autoriser tous les éléments et propriétés) ou CUSTOM_ELEMENTS_SCHEMA (pour autoriser des éléments ou propriétés avec un - dans leur nom)

id

Cette propriété vous permet de donner à un NgModule un identifiant unique, que vous pouvez utiliser pour récupérer une référence d'usine de module. C'est un cas d'utilisation rare actuellement

NgModule Examples

Pour illustrer la façon dont NgModule est utilisé avec Angular, regardons un ensemble d'exemples qui montrent comment gérer facilement différents cas d'utilisation.

Feature NgModules [19659034] Le cas d'utilisation le plus basique de NgModules en dehors du AppModule est pour Feature NgModules (habituellement appelés modules d'entités, mais essayant de garder les termes cohérents). Ils aident à séparer les différentes parties de votre application et sont fortement recommandés. Dans la plupart des cas, ils sont identiques à l'application principale NgModule. Jetons un coup d'œil à un Feature NgModule de base:

 @NgModule ({
  déclarations: [
    ForumComponent,
    ForumsComponent,
    ThreadComponent,
    ThreadsComponent
  ],
  importations: [
    CommonModule,
    FormsModule,
  ],
  exportations: [
    ForumsComponent
  ]
  fournisseurs: [
    ForumsService
  ]
})
classe d'exportation ForumsModule {}

Cette fonction simple NgModule définit quatre composants, un fournisseur et importe deux modules requis par les composants et le service. Ensemble, ils comprennent les éléments nécessaires pour la section des forums d'une application.

Les éléments des fournisseurs sont disponibles pour tous les NgModules qui importent le ForumsModule à injecter, mais c'est important pour comprendre que chaque NgModule aura sa propre instance de ce service. Ceci est différent des fournisseurs listés dans la racine NgModule, à partir de laquelle vous aurez toujours la même instance (à moins qu'elle ne soit réprimée). C'est là qu'il est important de comprendre l'injection de dépendance, en particulier injection hiérarchique de dépendance . Il est facile de penser que vous obtiendrez la même instance d'un service et que vous changerez de propriétés, mais ne verrez jamais les changements ailleurs dans l'application.

Comme nous l'avons appris plus tôt, les éléments des déclarations ne sont pas effectivement disponible pour être utilisé dans d'autres NgModules, car ils sont privés à ce NgModule. Pour résoudre ce problème, vous pouvez éventuellement exporter les déclarations que vous souhaitez consommer dans d'autres NgModules, comme dans cet extrait où il n'exporte que le ForumsComponent . Maintenant, dans tout autre Feature NgModules, vous pouvez mettre (ou n'importe quel sélecteur pour le composant) pour afficher le ForumsComponent dans un modèle.

Une autre différence clé est que ForumsModule importe le CommonModule au lieu du BrowserModule . Le BrowserModule ne devrait être importé qu'à la racine NgModule, mais le CommonModule contient les directives angulaires de base et les pipes (telles que NgFor et la Date pipe). Si votre Feature NgModule n'utilise aucune de ces fonctionnalités, il n'aura pas réellement besoin du CommonModule .

Maintenant, quand vous voulez consommer le ForumsModule dans votre projet, vous devez l'importer dans votre AppModule comme vous le voyez ici:

 @NgModule ({
  déclarations: [
    AppComponent
  ],
  importations: [
    BrowserModule,
    ForumsModule
  ],
  fournisseurs: [],
  bootstrap: [AppComponent]
})
classe d'exportation AppModule {}

Ce NgModule est ensuite importé dans le principal AppModule pour le charger correctement, ce qui inclut les éléments du tableau de fournisseurs ForumsModule et tous les éléments exportés à consommer dans votre application. [19659005] Lorsque vous utilisez l'interface CLI Angular, vous pouvez facilement générer des Feature NgModules en exécutant le générateur pour un nouveau NgModule:

 ng generate chemin du module / to / module / feature

Vous pouvez organiser votre Feature NgModules comme bon vous semble, mais la recommandation générale est de regrouper des choses similaires qui sont utilisées dans la même vue. J'essaie de créer un petit nombre de NgModules de fonctionnalité pour contenir les choses communément partagées, puis je me concentre davantage sur NgModules pour chaque caractéristique majeure de l'application

NgModules de chargement paresseux avec des routes

l'utilisateur en a besoin, et avec Angular, cela est actuellement possible en utilisant le routeur et les Feature NgModules ensemble. Le routeur a la capacité de charger des NgModules paresseux lorsqu'un utilisateur demande un itinéraire spécifique. Voir cette amorce sur le routage avec Angular si vous êtes nouveau dans le routage.

La meilleure façon de commencer est de créer un Feature NgModule pour les parties uniques d'un itinéraire. Vous pourriez même vouloir regrouper plus d'une route, si elles sont presque toujours utilisées ensemble. Par exemple, si vous avez une page de compte client avec plusieurs sous-pages pour gérer les détails du compte, plus que probablement vous les déclareriez dans le même NgModule.

Il n'y a aucune différence dans la façon de définir le NgModule lui-même. vous devrez définir quelques routes avec RouterModule.forChild () . Vous devriez avoir une route qui a un chemin vide, qui agira comme la route racine pour ce Feature NgModule, et toutes les autres routes s'y accrocheront:

 @NgModule ({
  déclarations: [
    ForumComponent,
    ForumsComponent,
  ],
  importations: [
    CommonModule,
    FormsModule,
    RouterModule.forChild([
      {path: '', component: ForumsComponent},
      {path: ':forum_id', component: ForumComponent}
    ])
  ],
  fournisseurs: [
    ForumsService
  ]
})
classe d'exportation ForumsModule {}

Il y a un changement de comportement important qui n'est pas évident lié à la manière dont les fournisseurs sont enregistrés avec l'application. Comme il s'agit d'un NgModule chargé paresseux, les fournisseurs ne sont pas disponibles pour le reste de l'application. Cette distinction est importante et doit être prise en compte lors de la planification de l'architecture de votre application. Comprendre comment fonctionne l'injection de dépendances Angular est très important ici.

Pour charger la route paresseuse, le AppModule principal définit le chemin qui va à ce Feature NgModule. Pour ce faire, vous devrez mettre à jour votre configuration de routeur racine pour un nouvel itinéraire. Cet exemple montre comment définir une route paresseuse, en lui attribuant un chemin et loadChildren propriétés:

 const routes: Routes = [
  {
    path: 'forums',
    loadChildren: 'app/forums/forums.module#ForumsModule'
  },
  {
    path: '',
    component: HomeComponent
  }
];

La syntaxe de la propriété loadChildren est une chaîne contenant le chemin du fichier NgModule (sans l'extension de fichier), un symbole # suivi du nom du NgModule class: loadChildren: 'chemin / vers / module # NomModule . Angular utilise ceci pour savoir où charger le fichier à l'exécution, et connaître le nom de NgModule.

Le chemin vers la route chargée paresseuse est défini au niveau racine des routes, donc le NgModule chargé paresseux ne sait même pas spécifiquement ce que le chemin pour son itinéraire sera. Cela les rend plus réutilisables, et permet à l'application de savoir quand charger paresseux ce NgModule. Pensez au NgModule chargé paresseux qui définit toutes les routes comme des chemins relatifs, et le chemin complet est fourni en combinant la route racine et les routes chargées paresseuses.

Par exemple, si vous visitez la route / dans cette application , il va charger le HomeComponent et le ForumsModule ne seront pas chargés. Cependant, une fois qu'un utilisateur clique sur un lien pour voir les forums, il remarquera que le chemin / forums nécessite que le ForumsModule soit chargé, télécharge et en enregistre les routes définies

Routing NgModules

Un modèle courant pour Angular est d'utiliser un NgModule séparé pour héberger toutes vos routes. C'est fait pour la séparation des préoccupations, et est entièrement facultatif. La CLI angulaire prend en charge la génération automatique d'un NgModule de routage lorsque vous créez un nouveau module en transmettant le drapeau - routing :

 ng generate chemin du module / to / module / feature --routing

Ce qui se passe, c'est que vous créez un NgModule autonome qui définit vos routes, puis votre Feature NgModule l'importe. Voici à quoi pourrait ressembler un NgModule de routage:

 const routes: Routes = [
  { path: '', component: ForumsComponent }
];

@NgModule ({
  importations: [RouterModule.forChild(routes)],
  exportations: [RouterModule]
})
classe d'exportation ForumsRoutingModule {}

Ensuite, il vous suffit de l'importer dans votre ForumsModule comme vous le voyez ici:

 @NgModule ({
  déclarations: [
    ForumComponent,
    ForumsComponent,
  ],
  importations: [
    CommonModule,
    FormsModule,
    ForumsRoutingModule,
  ],
  fournisseurs: [
    ForumsService
  ]
})
classe d'exportation ForumsModule {}

C'est en grande partie une préférence, mais c'est un modèle commun que vous devriez considérer. Essentiellement, c'est une autre façon que les NgModules sont utilisés pour la séparation de code.

Singleton services

Nous avons vu quelques soucis concernant les fournisseurs où vous ne pouviez pas être sûr que vous obtiendriez la même instance d'un service sur NgModules à moins que vous ne l'ayez fourni que dans la racine NgModule. Il existe un moyen de définir votre NgModule afin qu'il ne puisse déclarer les fournisseurs que pour la racine NgModule, mais ne pas les redéclarer pour tous les autres NgModules.

En fait, le routeur Angular en est un bon exemple. Lorsque vous définissez un itinéraire dans votre NgModule racine, vous utilisez RouterModule.forRoot (routes) mais à l'intérieur de Feature NgModules vous utilisez RouterModule.forChild (routes) . Ce modèle est commun pour toute bibliothèque réutilisable nécessitant une instance unique d'un service (singleton). Nous pouvons faire la même chose avec n'importe quel NgModule en ajoutant deux méthodes statiques à notre NgModule comme vous le voyez ici:

 @NgModule ({
  déclarations: [
    ForumComponent,
    ForumsComponent,
    ThreadComponent,
    ThreadsComponent
  ],
  importations: [
    CommonModule,
    FormsModule,
  ],
  exportations: [
    ForumsComponent
  ]
})
classe d'exportation ForumsModule {
  static forRoot (): ModuleWithProviders {
    revenir {
      ngModule: ForumsModule,
      fournisseurs: [ForumsService]
    }
  }

  static forChild (): ModuleWithProviders {
    revenir {
      ngModule: ForumsModule,
      fournisseurs: []
    }
  }
}

Puis dans notre AppModule vous définissez l'import avec la méthode forRoot () qui retournera le NgModule avec les fournisseurs. Dans tout autre NgModule qui importe ForumsModule vous utiliseriez la méthode forChild () pour ne plus déclarer le fournisseur (créant ainsi une nouvelle instance):

 @ NgModule ({
  déclarations: [
    AppComponent
  ],
  importations: [
    BrowserModule,
    ForumsModule.forRoot()
  ],
  fournisseurs: [],
  bootstrap: [AppComponent]
})
classe d'exportation AppModule {}

NgModules pour grouper NgModules

Vous pouvez combiner un certain nombre d'autres NgModules en un seul, pour faciliter l'importation et la réutilisation. Par exemple, dans le projet Clarity sur lequel je travaille, nous avons un certain nombre de NgModules qui n'exportent que d'autres NgModules. Par exemple, il s'agit du principal module ClarityModule qui réexpose en fait les autres NgModules individuels qui contiennent chacun des composants:

 @NgModule ({
  exportations: [
    ClrEmphasisModule, ClrDataModule, ClrIconModule, ClrModalModule, ClrLoadingModule, ClrIfExpandModule, ClrConditionalModule, ClrFocusTrapModule, ClrButtonModule, ClrCodeModule, ClrFormsModule, ClrLayoutModule, ClrPopoverModule, ClrWizardModule
  ]
})
classe d'exportation ClarityModule {}

Cela facilite l'importation de nombreux NgModules à la fois, mais cela rend plus difficile pour le compilateur de savoir quels NgModules sont utilisés ou non pour les optimisations d'agitation des arbres.

Résumé

Nous avons traversé un tourbillon Tour de NgModules en Angulaire, et couvert les cas d'utilisation clés. La documentation angulaire sur les NgModules est assez détaillée, et si vous êtes bloqué, je vous suggère de consulter la FAQ .

.




Source link