【Angular】サービスとは?「作成方法」や「使い方」などを解説!

この記事ではAngularの『サービス』について、以下の内容をサンプルコード用いてわかりやすく解説します。

  • Angularの「サービス」とは
  • Angularの「サービス」の使い方
  • @Injectableデコレーター内にprovidedIn: 'root'を記述しない場合のサービスの使い方

Angularの「サービス」とは

Angularにはサービスという便利な機能があります。

Angularのコンポーネントは見た目(テンプレート)の表示に専念し、ビジネスロジック(データの取得、データの変更、データの計算などをする処理)はサービスに任せるのが一般的です。

例えば、コンポーネント内で外部のWeb APIからデータを取得したり、複雑なデータを整形したりするのは好ましくありません。これらの処理はサービスに任せます。

コンポーネントにあるビジネスロジックをサービスに切り出すことで、コンポーネントは見た目(テンプレート)の表示に専念することができるようになります。

サービスの使用例としては以下のようなものが考えられます。

サービスの使用例

  • 商品(例えば本など)の情報を取得するサービス
    • BookService
  • チケットの予約を行うサービス
    • BookingService

この記事では、一例として、シンプルに「Hello Angular!」のみを出力するサービス(MessageService)の作成方法や使い方を説明します。

Angularの「サービス」の使い方

Angularの「サービス」を使用する手順を以下に示します。

Angularの「サービス」を使用する手順

  • サービスを作成する
  • サービスを編集する
  • サービスをコンポーネントに注入する

上記の手順について、順番に説明します。

サービスを作成する

まず、サービスの雛形を作成します。

カレントディレクトリ(現在作業しているディレクトリ)がプロジェクトのルートディレクトリであることを確認してください。その後、Angular CLIが提供している「ng generate serviceコマンド」を実行すると、サービスの雛形を作成することができます。以下のコマンドを実行してください。

ng generate service [サービス名]
# この記事では、MessageServiceというサービスを作成するので、以下のコマンドを実行しています。
ng generate service message

このコマンドを実行すると、「src/app」ディレクトリに「サービスファイル(message.service.ts)」と「サービスのユニットテストのファイル(message.service.spec.ts)」が作成されます。

作成された「サービスファイル(message.service.ts)」は以下の内容になっています。

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class MessageService {

  constructor() { }
}

上記のプログラムではAngularのInjectableがインポートされています。

また、クラス定義(export class MessageService)の前に@Injectableデコレーターを付与することで、MessageServiceはサービスクラスになります。これは、AngularがこのMessageServiceサービスクラスを他のサービスクラス・コンポーネント・モジュールに注入(inject)可能であることを示しています。

また、@Injectableデコレーター内のprovidedIn: 'root'MessageServiceサービスクラスがアプリケーションのルートインジェクターに登録されていることを示しており、このMessageServiceサービスクラスがアプリケーションのどこからでも利用可能なことを示しています。

「サービスのユニットテストのファイル(message.service.spec.ts)」は使わないので、削除してもOKです。

サービスを編集する

次に自動生成された「サービスファイル(message.service.ts)」を編集します。以下のプログラムは、今回作成したMessageServiceサービスクラスの一例です。

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class MessageService {
  message(): string {
    return 'Hello Angular!';
  }
}

サービスとして提供するべきメソッドを入力しています。上記のプログラムでは、Hello Angular!を返すmessageメソッドを定義しています。

今回は一例として、簡単なメソッドを書きましたが、一般的には外部サービスに問い合わせた結果などを取得するメソッドを記述します。

サービスをコンポーネントに注入する

次に、MessageServiceサービスクラスをコンポーネントに注入する必要があります。以下のプログラムは、今回作成したAppComponentコンポーネントクラスの一例です。

import { Component } from '@angular/core';
import { MessageService } from './message.service';

@Component({
  selector: 'app-root',
  template: `{{receiveMessage}}`,
})
export class AppComponent {
  receiveMessage: string | undefined;

  constructor(private messageService: MessageService) { }

  ngOnInit() {
    this.receiveMessage = this.messageService.message();
  }
}

サービスをコンポーネントに注入する手順を以下に示します。

サービスをコンポーネントに注入する手順

  • MessageServiceをインポートする
  • コンストラクタにサービス型の引数を追加する

上記の手順について、順番に説明します。

MessageServiceをインポートする

import { MessageService } from './message.service';

AppComponentコンポーネントクラスでMessageServiceサービスクラスを使用するためには、上記のプログラムのようにMessageServiceをインポートします。

コンストラクタにサービス型の引数を追加する

constructor(private messageService: MessageService) { }

次に、コンストラクタにサービス型(ここではMessageService)の引数を追加します。

上記のプログラムでは、MessageServiceサービスクラスのインスタンスをmessageServiceプロパティとして宣言し、同時にコンストラクタ内で初期化しています。これにより、このコンストラクタを持つクラス(ここでは、AppComponent)内において、this.message.~の形式でコンポーネントのどこからでもアクセスできるようになります。

privateアクセス修飾子は、その後に続くプロパティやメソッドがそのクラス内でのみアクセス可能であることを示しています。つまり、上記のプログラムでは、messageServiceプロパティはAppComponentコンポーネントクラス内でのみアクセス可能であることを示しています。

Angularのテンプレートからもmessageserviceプロパティにアクセスしたい場合には、publicアクセス修飾子にします。publicアクセス修飾子は、その後に続くプロパティやメソッドがどこからでもアクセス可能であることを示しています。

以上で準備が完了です。では実際にアプリを実行してみましょう。実行結果は以下のようになります。

プログラムの実行結果

Angularの「サービス」の使い方

【補足】下記のプログラムはどちらも同じ

TypeScriptのパラメータプロパティ(Parameter properties)を利用すると、クラスのコンストラクタ内で直接プロパティを宣言し、初期化することができます。これにより、コードが簡潔になり、その結果、可読性が向上します。

以下の例では、MessageServiceサービスクラスのインスタンスをmessageServiceプロパティとして宣言し、同時にコンストラクタ内で初期化しています。

constructor(private messageService: MessageService) { }

これは以下のようなコードと同じ意味を持ちます。

private messageService: MessageService;

constructor(messageService: MessageService){
  this.messageService = messageService;
}

@Injectableデコレーター内に「providedIn: 'root'」を記述しない場合

@Injectableデコレーター内にprovidedIn: 'root'を記述すると、サービスクラスがアプリケーションのどこからでも利用可能になります。

このprovidedIn: 'root'の指定を無くすと、モジュールやコンポーネントの中だけに利用範囲を限定させることができます。

モジュールの中のみでサービスを利用する場合

MessageServiceサービスクラスAppModuleモジュールを以下のように記述します。

MessageServiceサービスクラス

import { Injectable } from '@angular/core';

@Injectable() //「providedIn: 'root'」を削除
export class MessageService {
  message(): string {
    return 'Hello Angular!';
  }
}

上記のプログラムに示すように、@Injectableデコレーター内にあるprovidedIn: 'root'を削除します。

AppModuleモジュール

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { MessageService } from './message.service'; //MessageServiceサービスクラスをインポート

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [MessageService],  //@NgmoduleデコレーターのprovidersパラメータにMessageServiceサービスクラスを追加
  bootstrap: [AppComponent]
})
export class AppModule { }

上記のプログラムに示すように、MessageServiceサービスクラスをAppModuleモジュールに登録します。

MessageServiceサービスクラスをAppModuleモジュールに登録するには以下の手順で行います。

サービスクラスをAppModuleモジュールに登録する手順

  • サービスクラスをインポートする
  • Ngmoduleデコレーターのprovidersパラメータにサービスクラスを追加する

上記の手順について、順番に説明します。

サービスクラスをインポートする

import { MessageService } from './message.service';

まず、上記に示すようにMessageServiceサービスクラスをインポートします。

Ngmoduleデコレーターのprovidersパラメータにサービスクラスを追加する

providers: [MessageService],

次に、@NgmoduleデコレーターのprovidersパラメータにMessageServiceサービスクラスを追加します。

このように記述することで、モジュール(ここでは、AppModule)の全体でサービスを利用できるようになります。

コンポーネントの中のみでサービスを利用する場合

MessageServiceサービスクラスAppComponentコンポーネントクラスを以下のように記述します。

MessageServiceサービスクラス

import { Injectable } from '@angular/core';

@Injectable() //「providedIn: 'root'」を削除
export class MessageService {
  message(): string {
    return 'Hello Angular!';
  }
}

上記のプログラムに示すように、@Injectableデコレーター内にあるprovidedIn: 'root'を削除します。

AppComponentコンポーネントクラス

import { Component } from '@angular/core';
import { MessageService } from './message.service';

@Component({
  selector: 'app-root',
  template: `{{receiveMessage}}`,
  providers: [MessageService],  //@ComponentデコレーターのprovidersパラメータにMessageServiceサービスクラスを追加
})
export class AppComponent {
  receiveMessage: string | undefined;

  constructor(private messageService: MessageService) { }

  ngOnInit() {
    this.receiveMessage = this.messageService.message();
  }
}

@ComponentデコレーターのprovidersパラメータにMessageServiceサービスクラスを追加します。

providers: [MessageService],

この場合、サービスは現在のコンポーネント(ここでは、AppComponent)と子コンポーネントのみで利用できるようになります。

本記事のまとめ

この記事ではAngularの『サービス』について、以下の内容を説明しました。

  • Angularの「サービス」とは
  • Angularの「サービス」の使い方
  • @Injectableデコレーター内にprovidedIn: 'root'を記述しない場合のサービスの使い方

お読み頂きありがとうございました。