English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
angular2 Dependency injection includes too much content, one of the key points is the injector, and the injector is very difficult to understand. Today, we will not go deep into the content of the injector, and you can refer to the official documentation. Today, we will talk about the hierarchy of the injector.
That is, the container that the component uses to obtain the service will choose which one specifically.
First, let's briefly introduce a background: there is3The components include AppComponent (root component), DetailList component (log list component), and Detail component (log component).
These three components will form a component tree, and we can also consider that each component will have an independent injector (it may not appear, but we can think of it this way).
Add a logging service LoggerService, if we follow the usual entry-level method, we provide LoggerService in the root module providers. Then, LoggerService will have only one instance throughout the application. What does this mean? It means that no matter which component, the LoggerService obtained is the first created LoggerService, and all components share a service instance. This can sometimes be a useful feature, such as the global configuration we use.
Global unique is not the focus of our verification this time, because it is too common. What we want to explain this time is how we can obtain a separate LoggerService instance in each component, that is, each component's instance is different. This requires understanding ng2It is necessary to have some understanding of dependency injection.
Let's explain step by step how to achieve this?
In order to make it easier for those who can see this short article to understand, I have added some basic code.
1.app.module.ts The root module of the application. Note that we did not register loggerService in Providers. Of course, it can also achieve our purpose by registering it through the method behind.
import { NgModule, Optional, SkipSelf, ReflectiveInjector} from '@angular'/core'; import { BrowserModule } from '@angular'/platform-browser'; /* App Root */ import { AppComponent } from '.'/app.component'; import { routing } from './app.routing'; import { Title } from '@angular/platform-browser'; import {MessagesModule, GrowlModule, ButtonModule}from 'primeng/primeng'; import {AppDetailComponent}from './app-detail.component'; import {AppDetailListComponent}from './app-detailList.component'; import {LoggerService}from './logger.service'; let allTitle:string="郭志奇"; @NgModule({ imports: [ BrowserModule, MessagesModule, GrowlModule, ButtonModule ], declarations: [AppComponent, AppDetailComponent, AppDetailListComponent],//Déclarer les informations spécifiques de composants nécessaires au module actuel exports: [], providers: [Title], bootstrap: [AppComponent] } export class AppModule { constructor( @Optional() @SkipSelf() parentModule: AppModule) { console.log(parentModule); if (parentModule) { throw new Error( 'AppModule est déjà chargé. Importez-le uniquement dans AppModule'); } } }
2.app.component.ts - Composant racine de l'application
import { Component, ViewEncapsulation, Host, ViewContainerRef, ReflectiveInjector } from '@angular/core'; import { Title } from '@angular/platform-browser'; import { Message } from 'primeng/primeng'; import {LoggerService}from './logger.service'; @Component({ selector: 'my-app', moduleId: module.id, templateUrl: '.',/app.component.html', providers: [ { provide: LoggerService, useClass: LoggerService } ] } export class AppComponent {}} subtitle = '(Final)'; private msgs: Message[]; constructor(private title: Title, @Host() private logger: LoggerService) { this.title.setTitle("AppComponent"); } show(): void { this.logger.Debug(); } }
Veuillez noter que nous avons enregistré LoggerService dans les providers du composant racine.
3.app.detailList.ts LoggerService est également enregistré dans les providers de la liste de journalisation.
import {Component, Host}from '@angular/core'; import {LoggerService}from './logger.service'; @Component({ selector: 'my-detailList', templateUrl: '.',/app-detailList.component.html', moduleId: module.id, providers: [ { provide: LoggerService, useClass: LoggerService } ] } export class AppDetailListComponent { constructor(private logger: LoggerService) { } show(): void { this.logger.Debug(); } }
4.app.detail.ts Le composant de journalisation n'a pas enregistré LoggerService.
import {Component, Host}from '@angular/core'; import {LoggerService}from './logger.service'; @Component({ selector: 'detail', moduleId: module.id, templateUrl: '.',/app-detail.component.html', providers: [ // { provide: LoggerService, useClass: LoggerService } ] } export class AppDetailComponent { constructor(private logger: LoggerService) { } show(): void { this.logger.Debug(); } }
Maintenant, nous allons voir la hiérarchie de LoggerService avec Chrome.
En regardant le diagramme des dépendances, nous pouvons voir que le composant AppComponent utilise une instance distincte de LoggerService, le composant DetailList utilise également une instance distincte de LoggerService, tandis que le composant Detail utilise l'instance de LoggerService du composant parent DetailList.
Actuellement, nous n'avons pas atteint nos exigences. Nos exigences sont que chaque composant ait une instance distincte de LoggerService. Alors nous supposons que les providers du composant Detail sont ceux que nous avons oubliés d'entrer, il est difficile de trouver la cause. Alors nous ajoutons un @Host() pour limiter la portée de la recherche de l'injecteur.
Pour la recherche ascendante de l'injecteur, veuillez consulter la documentation officielle.
Pour faciliter le débogage, nous ajoutons @Host().
Le décorateur @Host() limite la recherche vers le composant hôte
detail.ts indique que le composant detail est ajouté avec le décorateur @Host()
import {Component, Host}from '@angular/core'; import {LoggerService}from './logger.service'; @Component({ selector: 'detail', moduleId: module.id, templateUrl: '.',/app-detail.component.html', providers: [ // { provide: LoggerService, useClass: LoggerService } ] } export class AppDetailComponent { constructor( @Host() private logger: LoggerService) { } show(): void { this.logger.Debug(); } }
Il affichera un message d'erreur indiquant que l'instance de LoggerService est introuvable, l'effet de @Host() est de limiter l'injecteur à trouver le composant actuel et de ne pas continuer à chercher plus haut. C'est pourquoi il apparaît une erreur de Providers introuvable.
Ajouté à la conclusion des providers, c'est ce que nous voulons obtenir.
A résolu parfaitement le problème de l'utilisation de services d'instances individuels par plusieurs composants.
Résumé :
1.Si vous souhaitez que le composant utilise le service seul, vous devez d'abord enregistrer ce service individuellement dans providers. C'est facile à comprendre
2.Pour mieux détecter les problèmes possibles, ajoutez le décorateur @Host() sur le service de composant, ce qui peut lever les informations d'erreur le plus tôt possible
3.Utiliser ng2outils de debug
4.Il faut clarifier les relations entre les composants, car les relations entre les composants différents peuvent entraîner des instances de services différentes
5.Les services doivent être de niveau module, pas de niveau application.
Merci de lire, j'espère que cela peut aider tout le monde, merci de votre soutien à ce site !