このガイドでは、Angularにおける依存性の注入の追加機能について説明します。
@Inject
を使用したカスタムプロバイダー
カスタムプロバイダーを使用すると、組み込みのブラウザAPIなど、暗黙的な依存関係に対して具体的な実装を提供できます。
次の例では、InjectionToken
を使用して、BrowserStorageService
内の依存関係としてlocalStorageブラウザAPIを提供します。
src/app/storage.service.ts
import { Inject, Injectable, InjectionToken } from '@angular/core';export const BROWSER_STORAGE = new InjectionToken<Storage>('Browser Storage', { providedIn: 'root', factory: () => localStorage});@Injectable({ providedIn: 'root'})export class BrowserStorageService { constructor(@Inject(BROWSER_STORAGE) public storage: Storage) {} get(key: string) { return this.storage.getItem(key); } set(key: string, value: string) { this.storage.setItem(key, value); }}
factory
関数は、ブラウザのウィンドウオブジェクトに添付されているlocalStorage
プロパティを返します。
Inject
デコレーターは、storage
コンストラクターパラメーターに適用され、依存関係のカスタムプロバイダーを指定します。
このカスタムプロバイダーは、実際のブラウザAPIと対話するのではなく、モックAPIのlocalStorage
を使用してテスト中にオーバーライドできます。
コンポーネントのDOM要素を注入する
開発者は避けるように努めていても、一部の視覚効果とサードパーティツールでは、直接DOMにアクセスする必要があります。 そのため、コンポーネントのDOM要素にアクセスする必要がある場合があります。
Angularは、@Component
または@Directive
の基になる要素を、ElementRef
インジェクショントークンを使用してインジェクションすることで公開します。
import { Directive, ElementRef } from '@angular/core';@Directive({ selector: '[appHighlight]'})export class HighlightDirective { constructor(private element: ElementRef) {} update() { this.element.nativeElement.style.color = 'red'; }}
前方参照を使用して循環した依存関係を解決する
TypeScriptでは、クラスの宣言順序が重要です。 定義されるまでは、クラスを直接参照できません。
これは、特に推奨される1ファイルにつき1クラスルールに従っている場合は通常問題ありません。 しかし、循環参照は避けられない場合があります。 たとえば、クラス'A'がクラス'B'を参照し、'B'が'A'を参照する場合、いずれか一方を最初に定義する必要があります。
AngularのforwardRef()
関数は、Angularが後で解決できる間接的な参照を作成します。
クラスが自分自身を参照する場合にも、同様の問題が発生します。
たとえば、providers
配列内です。
providers
配列は、@Component()
デコレーター関数のプロパティであり、クラス定義の前に表示される必要があります。
forwardRef
を使用して、このような循環参照を解消できます。
app.component.ts
providers: [ { provide: PARENT_MENU_ITEM, useExisting: forwardRef(() => MenuItem), },],