Angular2 小貼士-多級注入器

angular2 的依賴注入包含了太多的內容,其中的一個重點就是注入器,而注入器又很是難理解,今天咱們不深刻介紹注入器的內容,能夠參考官方文檔,咱們今天來講注入器的層級。html

也就是組件獲取服務的容器會選擇具體哪個。chrome

先簡單介紹一個背景:有3個組件AppComponent 根組件、DetailList組件 ( 日誌列表組件)、Detail組件( 日誌組件)。bootstrap

這三個組件會造成一個組件樹,對應的咱們也能夠認爲每一個組件都會有一個獨立的注入器(有時候不會出現,可是能夠這麼認爲)。angular2

加入一個日誌服務LoggerService,若是按照咱們普通的入門方式,在根模塊providers 中提供LoggerService。那麼在整個應用程序中,LoggerService只有一個實例,什麼意思呢?就是說不管在哪一個組件,獲取到的都是首次建立的LoggerService,全部組件共用一個服務實例,這有時候會是一個有用的特性,好比咱們使用的全局配置。app

 

全局惟一不是咱們此次要驗證的重點,由於這個太普通,咱們此次要說明的是咱們如何在每一個組件中都獲取單獨的LoggerService實例,即每一個組件的實例都不一樣。這個就須要對ng2的依賴注入有所瞭解才能夠。ide

咱們逐步來講明如何實現?工具

爲了便於看到這篇短文的同窗有所瞭解,我加入一些基礎代碼。學習

1.app.module.ts 應用程序根模塊。注意此處咱們沒有在Providers中註冊loggerService。固然註冊了經過後面的方法也能夠達到咱們的目的。測試

 1 import { NgModule, Optional, SkipSelf, ReflectiveInjector} from '@angular/core';
 2 import { BrowserModule } from '@angular/platform-browser';
 3 
 4 /* App Root */
 5 import { AppComponent } from './app.component';
 6 import { routing } from './app.routing';
 7 import { Title } from '@angular/platform-browser';
 8 import {MessagesModule, GrowlModule, ButtonModule}from 'primeng/primeng';
 9 import {AppDetailComponent}from './app-detail.component';
10 import {AppDetailListComponent}from './app-detailList.component';
11 import {LoggerService}from './logger.service';
12 let allTitle:string="郭志奇";
13 
14 @NgModule({
15   imports: [
16     BrowserModule,
17     MessagesModule,
18     GrowlModule, ButtonModule
19   ],
20   declarations: [AppComponent, AppDetailComponent, AppDetailListComponent],//聲明當前模塊須要的指定 組件信息
21   exports: [],
22   providers: [Title],
23   bootstrap: [AppComponent]
24 })
25 export class AppModule {
26   constructor( @Optional() @SkipSelf() parentModule: AppModule) {
27     console.log(parentModule);
28     if (parentModule) {
29       throw new Error(
30         'AppModule is already loaded. Import it in the AppModule only');
31     }
32   }
33 }

2.app.component.ts  應用程序根組件this

 1 import { Component, ViewEncapsulation, Host, ViewContainerRef, ReflectiveInjector } from '@angular/core';
 2 import { Title } from '@angular/platform-browser';
 3 import { Message } from 'primeng/primeng';
 4 import {LoggerService}from './logger.service';
 5 @Component({
 6     selector: 'my-app',
 7     moduleId: module.id,
 8     templateUrl: './app.component.html',
 9     providers: [
10         { provide: LoggerService, useClass: LoggerService }
11     ]
12 })
13 export class AppComponent {
14     subtitle = '(Final)';
15     private msgs: Message[];
16     constructor(private title: Title, @Host() private logger: LoggerService) {
17         this.title.setTitle("AppComponent");
18     }
19 
20     show(): void {
21         this.logger.Debug();
22     }
23 }

請注意,咱們在跟組件中providers中註冊了LoggerService。

3.app.detailList.ts  日誌列表中providers中也註冊了LoggerService

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  日誌組件providers沒有註冊LoggerService。

 1 import {Component, Host}from '@angular/core';
 2 import {LoggerService}from './logger.service';
 3 @Component({
 4     selector: 'detail',
 5     moduleId: module.id,
 6     templateUrl: './app-detail.component.html',
 7     providers: [
 8       //  { provide: LoggerService, useClass: LoggerService }
 9     ]
10 })
11 
12 export class AppDetailComponent {
13     constructor(   private logger: LoggerService) {
14 
15     }
16     show(): void {
17         this.logger.Debug();
18     }
19 
20 }

 

如今咱們經過chrome來看一下 LoggerService的層級關係。

 

經過查看依賴關係圖,咱們能夠看到AppComponent組件使用了單獨的LoggerService,DetailList組件也使用單獨的LoggerService 實例,而Detail組件使用的是父組件DetailList的LoggerService實例。

目前來看沒有達到咱們的要求,咱們的要求是每一個組件都有單獨的LoggerService實例,那麼咱們假設Detail組件的providers是咱們忘記輸入的,很難測試出緣由所在。那麼咱們加入一個@Host()來限制注入器的查找範圍。

對於注入器的向上查找方式,請參考官方文檔。

爲了便於調試,咱們加入@Host().

@Host 裝飾器將把往上搜索的行爲截止在 宿主組件

detail.ts 提示detail組件加入@Host()裝飾器

 1 import {Component, Host}from '@angular/core';
 2 import {LoggerService}from './logger.service';
 3 @Component({
 4     selector: 'detail',
 5     moduleId: module.id,
 6     templateUrl: './app-detail.component.html',
 7     providers: [
 8       //  { provide: LoggerService, useClass: LoggerService }
 9     ]
10 })
11 
12 export class AppDetailComponent {
13     constructor( @Host() private logger: LoggerService) {
14 
15     }
16     show(): void {
17         this.logger.Debug();
18     }
19 
20 }

會提示找不到LoggerService的實例,@Host()的做用就是限制注入器查找到當前組件就中止,不會繼續往上查找。因此會出現找不到Providers的錯誤。

加上providers 的結果就是咱們想要的了。

 

完美的解決了多組件使用單獨服務實例的問題。

 

總結:

1.若是要使組件單獨使用服務,那麼首先要在providers 中單獨註冊該服務。很容易理解

2.爲了更好的檢測可能出現的問題,在組件服務上加入@Host()裝飾器,能夠儘可能早的拋出錯誤信息

3.使用ng2的debug工具

4.要明確各組件之間的關係,由於不一樣的組件關係會致使服務的實例的不一樣

5.服務儘可能是模塊級,不是應用級。

 

angular2,一個值得學習的東西。

相關文章
相關標籤/搜索