Comment utiliser correctement L'Injection de dépendances (DI) En Angular2?

j'ai essayé de comprendre comment fonctionne L'Injection de dépendance (DI) En Angular2. J'ai rencontré beaucoup de problèmes chaque fois que j'ai essayé d'injecter un service ou une classe dans mes composants.

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

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

y a-t-il une règle empirique pour savoir quand utiliser quoi? Pourriez-vous donner un exemple de code snippet? Merci: -)

23
demandé sur Barna Tekse 2016-03-20 05:20:05

5 réponses

L'injection de dépendance

dans Angular2 repose sur des injecteurs hiérarchiques qui sont liés à l'arbre des composants.

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

  • Pour l'ensemble de l'application lors de l'amorçage. Dans ce cas, tous les sous-injecteurs (le composant) voir ce fournisseur et de partager l'instance associée. En interaction, ce sera la même instance
  • pour un élément spécifique et ses sous-éléments. Comme précédemment, 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 de bootstrapping par exemple), ce fournisseur sera utilisé à la place. Ainsi, vous pouvez remplacer les choses.
  • pour les services. Il n'y a pas de fournisseurs associés avec eux. Ils utilisent ceux de l'injecteur de l'élément déclencheur (directement = un composant ou indirectement = un composant qui déclenche l'appel de chaîne de service)

concernant vos autres questions:

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

voir ces questions pour plus de détails:

12
répondu Thierry Templier 2017-07-15 15:49:06

Broad question, TL; DR version


@Injectable()

  • est un décorateur qui indique le typescript que la classe décorée a dependencies et ne signifie pas que cette classe peut être injectée dans un autre.

  • et ensuite dactylographié comprend que il doit injecter les métadonnées nécessaires dans la classe décorée lors de la construction, en utilisant les dépendances imported .

bootstrap (app, [service])

  • bootstrap() s'occupe de créer un injecteur de racine pour notre application quand il est bootstrapped. Il prend une liste de fournisseurs comme deuxième argument qui sera transmis directement à l' injecteur quand il est créé.

  • vous démarrez votre application avec les services qui seront utilisés dans de nombreux endroits comme Http , ce qui signifie également que vous n'aurez pas besoin d'écrire providers: [Http] dans votre configuration de classe.

fournisseurs: [service]

  • en passant tous les arguments des services à Injector .

  • Vous mettez des services des fournisseurs s'il n'est pas bootstrap() ped. Et n'est nécessaire que dans quelques endroits.

@injection()

  • est aussi un décorateur une fonction qui fait le travail de l'injection de ces services

    pareil. constructor(@Inject(NameService) nameService)
  • mais si vous utilisez TS tout ce que vous devez faire est ce constructor(nameService: NameService) et dactylographier le reste.

Autres Lectures

Espérons que cette aide. :)

16
répondu Ankit Singh 2017-07-16 18:18:49

j'ai besoin d'utiliser les fournisseurs de: []

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

où vous enregistrez un fournisseur détermine la portée 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]) (racine)


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

si un fournisseur de soins est inscrit dans l'une des composantes pour enfants, une nouvelle instance (différente) est prévue pour les descendants de cette composante.

si un composant demande une instance (par un paramètre de constructeur), DI regarde" vers le haut " l'arbre du composant (à partir de la feuille vers la racine) et prend le premier fournisseur qu'il trouve. Si une instance pour ce provider a déjà été créée précédemment, cette instance est utilisée, sinon une nouvelle instance est créée.

@Inject ()

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

constructor(someField:SomeType) {}

DI cherche le fournisseur par le type SomeType . Si @Inject(SomeType) est ajouté

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

DI cherche le fournisseur par le paramètre passé à @Inject() . Dans l'exemple ci-dessus, le paramètre passé à @Inject() est le même que le type du paramètre, par conséquent, @Inject(SomeType) est redondant.

cependant il y a des situations où vous voulez personnaliser le comportement par exemple pour injecter un paramètre de configuration.

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

le type string n'est pas suffisant pour distinguer un paramètre de configuration spécifique lorsque vous avez plusieurs enregistrements.

La valeur de configuration doit être enregistrée comme fournisseur quelque part comme


>=RC.5

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

<=RC.4

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

à cet effet, vous n'avez pas besoin de @Inject() pour FormBuilder si le constructeur ressemble à

constructor(formBuilder: FormBuilder) {}
4
répondu Günter Zöchbauer 2016-09-01 06:33:50

j'ajouterai quelques choses que je n'ai pas vu mentionnées dans les autres réponses. (Au moment où j'écris ceci, cela signifie les réponses de Thierry, Günter, et A_Singh).

  • toujours ajouter Injectable() aux services que vous créez. Bien qu'il ne soit nécessaire que si votre service lui-même a besoin d'injecter quelque chose, c'est une bonne pratique 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 les fournisseurs qui ne sont pas intégrés. (Exemples d'objets que nous n'avons pas de registre ElementRef , ApplicationRef , etc. On peut simplement les injecter.)
  • quand un composant a un providers tableau, alors ce composant obtient 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 à l'arbre de l'injecteur comme un arbre plus clairsemé que le composant de l'arbre. Le premier injecteur qui peut satisfaire une dépendance à la demande. Cette hiérarchie d'injecteurs permet aux dépendances d'être des singletons ou non.
2
répondu Mark Rajcok 2016-10-11 01:15:14

Pourquoi @Injectable ()?

@Injectable () marque une classe comme disponible à un injecteur pour instantiation. En général, un injecteur signalera une erreur en essayant d'instancier une classe qui n'est pas marquée comme @Injectable().

il se trouve que nous aurions pu omettre @Injectable() de notre première version D'HeroService parce qu'elle n'avait pas de paramètres injectés. Mais nous devons l'avoir maintenant que notre service a une dépendance injectée. Nous en avons besoin parce que L'Angular nécessite des métadonnées de paramètre de constructeur pour injecter un Logger.

SUGGESTION: AJOUTER @INJECTABLE () À CHAQUE CLASSE DE SERVICE Nous recommandons d'ajouter @Injectable () à chaque classe de service, même ceux qui n'ont pas de dépendances et, par conséquent, ne l'exigent pas techniquement. Voici pourquoi:

vérification Future: Pas besoin de se rappeler @Injectable() quand on ajoute une dépendance plus tard.

cohérence: tous les services suivent la mêmes règles, et nous n'avons pas à se demander pourquoi un décorateur est manquant.

Les injecteurs

sont également responsables de l'instanciation de composants comme HeroesComponent. Pourquoi N'avons-nous pas marqué HeroesComponent comme @Injectable()?

nous pouvons l'ajouter si nous le voulons vraiment. Ce n'est pas nécessaire car le Component HeroesComponent est déjà marqué avec @Component, et cette classe decorator (comme @Directive et @Pipe, que nous verrons plus tard) est un sous-type de métadonnées injectables. Ce sont en effet les décorateurs de Métrométéinjectables qui identifient une classe comme cible pour une instanciation par un injecteur.

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

0
répondu stackdave 2016-08-21 04:14:58