コンテンツへスキップ
異なる種類のAngularサービス提供者の簡素化

異なる種類のAngularサービス提供者の簡素化

Angular Service プロバイダーは、依存関係値のランタイム バージョンを提供します。したがって、サービスを挿入すると、Angularインジェクターはプロバイダーを参照してサービスのインスタンスを作成します。

読書6分

Angular Service プロバイダーは、依存関係値のランタイム バージョンを提供します。したがって、サービスを挿入すると、Angularインジェクターはプロバイダーを参照してサービスのインスタンスを作成します。

コンポーネント、パイプ、または指令にランタイムでどのインスタンスや値を注入すべきかを決定するのはプロバイダーです。ここには多くの専門用語が関わっているので、プロバイダーの種類の目的を理解するために、まずはサービスの作成から始めましょう。 例えば、エラーメッセージをログに記録するErrorServiceというサービスがあるとします。

import { Injectable } from '@angular/core';
 
@Injectable()
export class ErrorService {
 
    logError(message: string) {
        console.log(message);
    }
}

さて、このサービスをコンポーネントで利用できます。以下のリストに示されています:

import { Component } from '@angular/core';
import { ErrorService } from './errormessage.service';
 
@Component({
    selector: 'app-root',
    template: `
  <input [(ngModel)]='err' type='text'/>
  <button (click)='setError()'>set error</button>
  `,
    providers: [ErrorService]
})
export class AppComponent {
    constructor(private errorservice: ErrorService) { }
    err: string;
    setError() {
        this.errorservice.logError(this.err);
    }
 
}

サービスをインポートし、プロバイダー配列に渡し、コンポーネントのコンストラクタに注入しています。私たちはボタンをクリックするだけでサービスメソッドを呼び出しており、コンソールでエラーメッセージが出ているのを確認できます。とてもシンプルですよね?

ここでは、コンポーネント(またはモジュール)のプロバイダー配列に渡される値Angular、実行時にどのインスタンスを注入すべきかを判断します。

「提供者は、特定のトークンのオブジェクトがどのように作成できるかを決定する。」

例えば、プロバイダーのコンポーネントまたはモジュールの配列にサービス名を渡すと、以下のように:

providers: [ErrorService]

ここでは、Angularトークン値 ErrorService を使用し、トークン ErrorService に対して ErrorService クラスのオブジェクトを作成します。上記の構文は以下の構文のショートカットです:

providers: [{
    provide: ErrorService, useClass: ErrorService
}]

提供プロパティは、の鍵として機能するトークンを保持します。

  1. 依存関係値の特定。
  2. registering the dependency.

2つ目の性質(4つのタイプがあります)は依存関係値を作成するために使われます。第二パラメータには以下の4つの可能な値があります。

  1. useClass
  2. 使用現存
  3. useValue
  4. useFactory

先ほどuseClassの例を見ました。次に、より良いエラーログのための新しいクラス「NewErrorService」があるとします。

import { Injectable } from '@angular/core';
 
@Injectable()
export class NewErrorService {
 
    logError(message: string) {
        console.log(message);
        console.log('logged by DJ');
    }
 
}

使用現存

ここで、ErrorServiceのインスタンスの代わりにNewErrorServiceのインスタンスを注入したいと考えています。 また、理想的には両方のクラスが同じインターフェースを実装している必要があり、つまり異なる実装で同じメソッド署名を持つ必要があります。 そこで、トークンErrorServiceに対してNewErrorServiceのインスタンスを注入したいのです。以下のようにuseClassを使って実行できます:

providers: [
    NewErrorService,
    { provide: ErrorService, useClass: NewErrorService }
]

上記のアプローチの問題は、NewErrorServiceのインスタンスが2つ存在することです。これはuseExistingを使うことで解決できます。

providers: [
    NewErrorService,
    { provide: ErrorService, useExisting: NewErrorService }
]

これでNewErrorServiceは1つだけになり、トークンとしてErrorServiceのNewErrorServiceインスタンスが作成されます。

コンポーネントをNewErrorServiceに改造させてください。

import { Component } from '@angular/core';
import { ErrorService } from './errormessage.service';
import { NewErrorService } from './newerrormessage.service';
 
@Component({
    selector: 'app-root',
    template: `
  <input [(ngModel)]='err' type='text'/>
  <button (click)='setError()'>set error</button>
  <button (click)='setnewError()'>Set New eroor</button>
  `,
    providers: [
        NewErrorService,
        { provide: ErrorService, useExisting: NewErrorService }
    ]
})
export class AppComponent {
    constructor(private errorservice: ErrorService, private newerrorservice: NewErrorService) { }
    err: string;
    setError() {
        this.errorservice.logError(this.err);
    }
    setnewError() {
        this.newerrorservice.logError(this.err);
    }
 
}

ここではデモンストレーションのためにコンポーネントにサービスを注入していますが、モジュールレベルでのサービスを使うにはモジュール自体に注入できます。そして、set errorボタンをクリックするとNewErrorServiceが呼ばれます。

useValue

useClassもuseExistnも、特定のトークンに対して注入するサービスクラスのインスタンスを作成しますが、時にはインスタンスを作成するのではなく直接値を渡したい場合もあります。したがって、クラスのインスタンスではなくReadymade Objectを渡したい場合は、以下のリストに示すようにuseValueを使うことができます。

providers: [
    {
        provide: ErrorService, useValue: {
            logError: function (err) {
                console.log('inhjected directly ' + err);
            }
        }
    }

ここでは、useValueを使って既製オブジェクトを注入しています。したがって、トークンErrorServiceの場合、Angularオブジェクトを注入します。

useFactory

実行時までどのインスタンスが必要か分からない状況もあるかもしれません。最後の瞬間まで持っていない情報に基づいて依存を生み出さなければなりません。例えば、ユーザーがログインしている場合はServiceA、ログインしていない場合はServiceBのインスタンスを作成する必要がある場合を考えてみましょう。ログインユーザーに関する情報は、最終回まで利用できない場合や、アプリケーション使用中に変更される場合があります。

依存関係に関する情報が動的の場合はuseFactoryを使う必要があります。先ほどの例で使われた2つのサービスを考えてみましょう。

  1. ErrorMessageService
  2. NewErrorMessageService

特定の条件でトークンErrorServiceの場合、ErrorMessageServiceまたはnewErrorMessageServiceのいずれかのインスタンスが必要です。以下のリストに示されているようにuseFactoryを使えばそれを実現できます:

providers: [
    {
        provide: ErrorService, useFactory: () => {
            let m = 'old'; // this value can change
            if (m === 'old') {
                return new ErrorService();
            } else {
                return new NewErrorService();
            }
        }
    }
]

ここでは非常にハードコードされた条件を取り上げています。特定のトークンに対して動的にインスタンスを作成するための複雑な条件があるかもしれません。 また、useFactoryでは依存関係をクリアできることも覚えておいてください。ErrorServiceトークンのインスタンスを作成するためにLoginServiceに依存していると仮定してください。その場合、LoginServiceは以下のリストに示されるdeps配列です。

providers: [
    {
        provide: ErrorService, useFactory: () => {
            let m = 'old'; // this value can change
            if (m === 'old') {
                return new ErrorService();
            } else {
                return new NewErrorService();
            }
        },
        deps: [LoginService]
    }
]

これらはAngularの提供者と協働する4つの方法です。 この投稿が役に立てば幸いです。読んでくださってありがとうございます。 もしこの投稿が気に入ったら、ぜひシェアしてください。また、Infragistics Ignite UI for Angular Componentsをまだチェックしていない方は、ぜひチェックしてください!ウェブアプリをより速くコーディングできる30+のマテリアルベースのAngularコンポーネントがあります。

デモを予約