web-dev-qa-db-fra.com

Comment utiliser correctement l'injection de dépendance (DI) dans Angular2?

J'ai essayé de comprendre le fonctionnement de l'injection de dépendance (DI) dans Angular2. J'ai rencontré beaucoup de problèmes chaque fois que j'ai essayé d'injecter un service/ou une classe dans mes composants. 

À partir de différents articles googlé, je dois soit utiliser providers: [] dans la configuration du composant, soit parfois utiliser @Inject() dans mon constructeur ou injecter directement dans bootstrap(app, [service])? J'ai aussi vu des articles qui voulaient que je mette @injectable décorator. 

Par exemple: pour injecter Http, je n'ai besoin que de import{Http} et de mettre Http dans les fournisseurs, mais pour FormBuilder, je dois utiliser @Inject() dans le constructeur.

Y at-il une règle de base pour quand utiliser quoi? Pourriez-vous s'il vous plaît fournir un exemple d'extrait de code? Je vous remercie :-)

24
George Huang

L'injection de dépendance dans Angular2 repose sur des injecteurs hiérarchiques liés à l'arborescence des composants.

Cela signifie que vous pouvez configurer les fournisseurs à différents niveaux:

  • Pour toute l'application lors de l'amorçage. Dans ce cas, tous les sous-injecteurs (les composants) verront ce fournisseur et partageront l'instance associée. Lors de l'interaction, ce sera la même instance
  • Pour un composant spécifique et ses sous-composants. Comme auparavant mais pour un composant spécifique. Les autres composants ne verront pas ce fournisseur. Si vous redéfinissez quelque chose défini ci-dessus (lors du démarrage par exemple), ce fournisseur sera utilisé à la place. Vous pouvez donc passer outre aux choses.
  • Pour les services. Aucun fournisseur ne leur est associé. Ils utilisent l'un des injecteurs de l'élément qui déclenche (directement = un composant ou indirectement = un composant qui déclenche l'appel de la chaîne de service)

En ce qui concerne vos autres questions:

  • @Injectable. Pour s'introduire dans une classe, vous avez besoin d'un décorateur. Les composants en ont un (le @ Composant) mais les services sont de simples classes. Si un service nécessite l’injection de dépendances, vous avez besoin de ce décorateur.
  • @Injecter. Dans la plupart des cas, le type de paramètres de constructeur est suffisant pour laisser Angular2 déterminer ce qu’il faut injecter. Dans certains cas (par exemple, si vous utilisez explicitement un OpaqueToken et non une classe pour enregistrer des fournisseurs), vous devez spécifier des astuces sur ce qu'il faut injecter. Dans ce cas, vous devez utiliser @Inject.

Voir ces questions pour plus de détails:

13
Thierry Templier

Je dois soit utiliser les fournisseurs: [] 

Pour que l'injection de dépendance puisse créer des instances pour vous, vous devez enregistrer les fournisseurs pour ces classes (ou autres valeurs) quelque part.

L'emplacement où vous enregistrez un fournisseur détermine l'étendue de la valeur créée . Angulars DI est hiérarchique.
Si vous enregistrez un fournisseur à la racine de l’arbre 


> = RC.5

@NgModule({
  providers: [/*providers*/]
  ...
})

ou pour les modules chargés paresseux

static forRoot(config: UserServiceConfig): ModuleWithProviders {
  return {
    ngModule: CoreModule,
    providers: [
      {provide: UserServiceConfig, useValue: config }
    ]
  };
}

<= RC.4

(bootstrap(AppComponent, [Providers}) ou @Component(selector: 'app-component', providers: [Providers]) (composant racine) 


alors tous les composants et services qui demandent une instance obtiennent la même instance.

Si un fournisseur est enregistré dans l'un des composants enfants, une nouvelle instance (différente) est fournie aux descendants de ce composant.

Si un composant demande une instance (par un paramètre constructeur), DI examine "vers le haut" l'arborescence du composant (en partant de la feuille vers la racine) et prend le premier fournisseur trouvé. Si une instance pour ce fournisseur a déjà été créée précédemment, cette instance est utilisée, sinon une nouvelle instance est créée.

@Injecter()

Lorsqu'un composant ou un service demande une valeur à DI comme

constructor(someField:SomeType) {}

DI recherche le fournisseur selon le type SomeType. Si @Inject(SomeType) est ajouté

constructor(@Inject(SomeType) someField:SomeType) {}

DI recherche le fournisseur en fonction du paramètre passé à @Inject(). Dans l'exemple ci-dessus, le paramètre passé à @Inject() est identique au type du paramètre; par conséquent, @Inject(SomeType) est redondant.

Cependant, il existe des situations dans lesquelles vous souhaitez personnaliser le comportement, par exemple pour injecter un paramètre de configuration.

constructor(@Inject('someName') someField:string) {}

Le type string ne suffit pas pour distinguer un paramètre de configuration spécifique lorsque vous en avez plusieurs.
La valeur de configuration doit être enregistrée en tant que fournisseur quelque part comme


> = RC.5

@NgModule({
  providers: [{provide: 'someName', useValue: 'abcdefg'})]
  ...
})
export class AppModule {}

<= RC.4

bootstrap(AppComponent, [provide('someName', {useValue: 'abcdefg'})])

Par conséquent, vous n'avez pas besoin de @Inject() pour FormBuilder si le constructeur ressemble à

constructor(formBuilder: FormBuilder) {}
4
Günter Zöchbauer

Je vais ajouter quelques éléments que je n'ai pas vus mentionnés dans les autres réponses. (Au moment où j'écris ceci, cela signifie les réponses de Thierry, Günter et A_Singh).

  • Ajoutez toujours Injectable() aux services que vous créez. Bien que cela ne soit nécessaire que si votre service lui-même doit injecter quelque chose, il est recommandé de toujours l'inclure.
  • Le tableau providers sur les directives/composants et le tableau providers dans NgModules sont les deux seules façons d’enregistrer des fournisseurs qui ne sont pas intégrés. (Des exemples d'objets intégrés que nous n'avons pas à enregistrer sont ElementRef, ApplicationRef, etc. Nous pouvons simplement les injecter.)
  • Lorsqu'un composant a un tableau providers, il reçoit un injecteur angulaire. Les injecteurs sont consultés lorsque quelque chose veut injecter une dépendance (comme spécifié dans le constructeur). J'aime penser que l'arbre d'injection est un arbre plus éparse que l'arbre des composants. Le premier injecteur pouvant satisfaire une demande de dépendance le fait. Cette hiérarchie d'injecteurs permet aux dépendances d'être singletons ou non.
2
Mark Rajcok

Pourquoi @Injectable ()?

@Injectable () marque une classe comme disponible pour un injecteur pour une instanciation. En règle générale, un injecteur signale une erreur lorsqu'il tente d'instancier une classe qui n'est pas marquée comme @Injectable ().

En l'occurrence, nous aurions pu omettre @Injectable () de notre première version de HeroService car elle ne contenait aucun paramètre injecté. Mais nous devons l'avoir maintenant que notre service a une dépendance injectée. Nous en avons besoin car Angular nécessite des métadonnées de paramètre de constructeur afin d'injecter un enregistreur.

SUGGESTION: AJOUTEZ @INJECTABLE () À CHAQUE CATÉGORIE DE SERVICES Nous vous recommandons d’ajouter @Injectable () à chaque classe de service, même celles qui ne possèdent pas de dépendances et qui, par conséquent, ne le nécessitent pas techniquement. Voici pourquoi:

Vérification future: inutile de se souvenir de @Injectable () lorsque nous ajoutons une dépendance ultérieurement.

Cohérence: tous les services suivent les mêmes règles et nous n’avons pas à nous demander pourquoi il manque un décorateur.

Les injecteurs sont également responsables de l'instanciation de composants tels que HeroesComponent. Pourquoi n'avons-nous pas marqué HeroesComponent avec @Injectable ()?

Nous pouvons l'ajouter si nous le souhaitons vraiment. Ce n'est pas nécessaire car HeroesComponent est déjà marqué avec @Component et cette classe de décorateur (comme @Directive et @Pipe, que nous verrons plus tard) est un sous-type de InjectableMetadata. Ce sont en fait les décorateurs InjectableMetadata qui identifient une classe en tant que cible pour une instanciation par un injecteur.

Source: https://angular.io/docs/ts/latest/guide/dependency-injection.html

0
stackdave