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 :-)
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:
En ce qui concerne vos autres questions:
Voir ces questions pour plus de détails:
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) {}
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).
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.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.)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.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