web-dev-qa-db-ja.com

Angular 6: 'root'にHTTP_INTERCEPTORSを提供

AppModuleでサービスを提供するAngular 5から@Injectableデコレータで 'provideIn'キーを設定するAngular 6に変更すると、すべてのサービスが新しい "provideIn"メソッドを使用するように変更されます。ただし、私のインターセプターサービスは例外です。

「ルート」にHTTP_INTERCEPTORSトークンを提供し、InterceptorServiceを使用するにはどうすればよいですか?

これはatmを使用するAngular 5の方法です。

@Injectable()
export class InterceptorService implements HttpInterceptor {
...
}

appModule内:

providers: [{
  provide: HTTP_INTERCEPTORS,
  useClass: InterceptorService,
  multi: true
}]

しかし、Angular 6ウェイとは何でしょうか?

私は次のようなものを試しました

@Injectable({
  provideIn: 'root',
  useValue: HTTP_INTERCEPTORS,
  deps: [forwardRef(() => InterceptorService)]
})
export class InterceptorService implements HttpInterceptor {
...
}

injectableを含む他の多くの亜種が、オブジェクトリテラルをモジュールのプロバイダーに直接書き込むことなく動作させる方法を理解できないようです。

9
Miloš Tomšik

Angular 6のprovideIn- propertyは、Angular 5.の動作への単なる追加です。既存のInjectionTokenの場合、{ provide: ClassA, useClass: ClassB }構文を使用する必要があります。

-> https://angular.io/guide/dependency-injection-in-action#external-module-configuration を参照してください

tl; dr:HTTP_INTERCEPTORSを提供する方法は、Angular 6で変更されておらず、「Angular 6」の方法はありません。

4
Leon

インターセプターで

@Injectable()
export class InterceptorService implements HttpInterceptor {
...
}

アプリ内モジュール

providers: [{
  provide: HTTP_INTERCEPTORS,
  useClass: InterceptorService,
  multi: true
}]

"providedIn ...はAngularルートインジェクターが[サービス]のインスタンスを作成する責任があることを伝えます。この方法で提供されるサービスは、アプリケーション全体で自動的に利用可能になります。モジュールにリストする必要があります。」

「サービスの@Injectableデコレータでプロバイダーを構成できない場合は、アプリケーション全体のプロバイダーをAppComponentではなくルートAppModuleに登録します。通常、ルートアプリケーションコンポーネントではなくNgModuleにプロバイダーを登録します。」

さらに、サービスの範囲をアプリケーションの機能またはブランチに限定する必要がある場合は、そのブランチ/機能の最上位コンポーネントでそのサービスを提供します

https://angular.io/guide/dependency-injection-in-action

2
Ian Flynn

ここで注意すべき点がいくつかあります。

1. _providedIn: 'root'_は素晴らしい機能ですが、おそらくあなたのために構築されたのではありません

@Leonが言及したように、この機能は、サービスをより揺るぎないものにすることを目的としています。モジュールの_providers: []_プロパティを使用して完全に置き換えるものではありません。これは主にライブラリ開発者向けのオプションであり、アプリケーション開発者向けではありません。

このシナリオを想像してください:

数か月前にサービスを作成しましたが、アプリはそれを使用しなくなりました。それはあなたのアプリであり、コードベースを完全に理解し制御しているため、それを使用していないことを知っています。そのサービスに対して何をしますか?

A)_providedIn: 'root'_を使用していることを確認してください。これでAngularはもう使用しないので、バンドルからツリーシェイクすることができます

B)サービスを削除します。

私の推測はBです!

別のシナリオを想像してください:

サードパーティを使用していますAngular npmパッケージのモジュール。このモジュールには、アプリでその機能を利用するために使用できる12の異なるサービスがあります。アプリにはこれらのすべての機能は必要ありませんしたがって、これらのサービスタイプのうち3つだけをアプリケーションコンポーネントまたはサービスに注入します。

これをどのように解決しますか?

A)リポジトリをフォークして、アプリが使用しないすべてのサービスを削除できるようにします。そのため、バンドルに含める必要はありません。

B)プロジェクトオーナーに_providedIn: 'root'_の使用を依頼します。ライブラリ作成者が_providedIn: 'root'_を使用した場合、使用しないサービスはバンドルサイズに影響を与えず、必要に応じて他のチームが使用するためにnpmパッケージ/ Angularモジュールにとどまることができます。

私の推測はBです!

2. _providedIn: 'root'_はインターセプターでは機能しません

インターセプターはmulti DIトークンサービスです。つまり、同じDIトークンに対して複数の値を提供できます。そのトークンは_HTTP_INTERCEPTORS_です。 @Injectable({...})デコレータは、@NgModule({...})デコレータが行うように、異なるトークンに装飾された型を提供するAPIを公開しません。

これは、@Injectable({...})デコレーターを使用してAngular _Anywhere you would normally ask for 'HTTP_INTERCEPTORS' add this service to the set of values to use instead_]を伝えることができないことを意味します。

これは@NgModule({...})デコレータでのみ実行できます。

3.インターセプターの提供は順序に依存します

インターセプターはパイプラインであり、要求オブジェクト(変更または検査)および応答オブジェクト(変更または検査)へのアクセスを取得する順序を決定する際に提供される順序です。

一部のインターセプターは順序にとらわれない場合がありますが、おそらくその順序で決定性が必要です。

したがって、_providedIn: 'root'_がインターセプターで機能したとしても、それらが提供される順序はAngularコンパイルステップ中の型の解決順序によって決まります-おそらくあなたが望むものではありません。

代わりに、@NgModule({...})デコレータの_providers: []_配列でそれらを提供することは、それらが呼び出される順序を明示的に設定できることを意味します。

2
seangwright