Angularチュートリアルその5 サービス

Angularをチュートリアルを使って勉強する機会があったので、その時の内容について説明していきます。

Angularの本家サイトのチュートリアルの「Service」の説明をしていきたいと思います。

Angularではコンポーネントでデータの取得や更新をすべきではないので、データの取得や更新を行うServiceを作成します。このServiceを利用してデータの取得や更新を行っていきたいと思います。

本家サイトはこちらになります。

作成するプロジェクトは「Tour of Heroes」というアプリケーションです。

作成するアプリの概要についてはこちらから確認できます。

では、早速始めていきたいと思います!

開発環境

  • macOS Sierra 10.12.6
  • node 8.4.0
  • npm 5.3.0
  • Angular 4.3.6

サービスの作成

下記コマンドを実行してServiceを作成します。

$ ng generate service hero

そうすると「hero.service.ts」というファイルが作成されます。

中身はこんな感じです。

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

@Injectable()
export class HeroService {

  constructor() { }

}

hero dataの取得

hero.service.tsを編集してhero dataを取得できるようにします。

まずは必要なクラスをインポートします。

import { Hero } from './hero';
import { HEROES } from './mock-heroes';

次に、herosのモックを取得する関数を実装します。

getHeroes(): Hero[] {
  return HEROES;
}

HeroServiceの供給

module=appオプションを利用すると、AppModuleHeroServiceprovidersとして追加されます。

ng generate service hero --module=app

手動で追加する場合は、AppModuleを下記のように編集します。

providers: [ HeroService ],

HeroesComponentの更新

HeroesComponentの方も矛盾が内容に修正していきます。

HEROESを削除して、HeroServiceをインポートします。

import { HeroService } from '../hero.service';

heroesプロパティも下記のように修正します。

heroes: Hero[];

constructorHeroServiceをパラメータとして追加します。

constructor(private heroService: HeroService) { }

getHeroes()というメソッドを追加します。

getHeroes(): void {
  this.heroes = this.heroService.getHeroes();
}

先ほど追加したgetHeroes()ngOnInitの中で実行します。

ngOnInit() {
  this.getHeroes();
}

これでHeroesComponentを呼び出した際に、一覧を取得することができるようになります。

画面を確認すると一覧が表示されています。

観測可能なデータ

これまでの処理で同期的に一覧を取得することはできましたが、非同期で一覧を取得するようなアプリの場合はうまく動かないので、HeroServiceを改良していきます。

下記のインポート文を追加します。

import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';

getHeroesメソッドも変更します。

getHeroes(): Observable<Hero[]> {
  return of(HEROES);
}

HeroesComponentgetHeroesメソッドも変更します。

getHeroes(): void {
  this.heroService.getHeroes()
      .subscribe(heroes => this.heroes = heroes);
}

メッセージの表示

画面の下の部分にメッセージを表示するコンポーネントを追加して、Serviceを利用してメッセージを表示させます。

MessagesComponentの作成

下記コマンドを実行してMessagesComponentを作成します。

ng generate component messages

app.component.htmlというファイルを下記のように変更します。

<h1>{{title}}</h1>
<app-heroes></app-heroes>
<app-messages></app-messages>

MessageServiceの作成

下記コマンドを実行してMessageServiceを作成します。

ng generate service message --module=app

作成されたmessage.service.tsというファイルを下記のように修正します。

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

@Injectable()
export class MessageService {
  messages: string[] = [];

  add(message: string) {
    this.messages.push(message);
  }

  clear() {
    this.messages = [];
  }
}

HeroServiceへMessageServiceを注入する

hero.service.tsMessageServiceをインポートします。

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

HeroServiceconstructorのパラメータにMessageServiceを追加します。

constructor(private messageService: MessageService) { }

HeroServiceからメッセージを送る

getHeroesメソッド実行時に、HeroServiceからMessageServiceへメッセージを送信できるようにします。

getHeroes(): Observable<Hero[]> {
  // Todo: send the message _after_ fetching the heroes
  this.messageService.add('HeroService: fetched heroes');
  return of(HEROES);
}

HeroServiceからメッセージを表示する

メッセージを表示するためにMessageComponentを下記のように変更します。

MessageServiceをインポートします。

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

constructorも変更します。

constructor(public messageService: MessageService) {}

MessageServiceのバインド

MessageServiceをバインドして、メッセージを画面上に表示できるようにしていきます。

messages.component.htmlを下記のように修正します。

<div *ngIf="messageService.messages.length">

  <h2>Messages</h2>
  <button class="clear"
          (click)="messageService.clear()">clear</button>
  <div *ngFor='let message of messageService.messages'> {{message}} </div>

</div>

完成イメージ

チュートリアルが完了するとこんな感じで動きます。

ソースコードについて

今までのソースコードはGithubにあげてますので、詳細を確認したい方はこちらからソースコードを見てもらえればと思います。

最後に

今回のチュートリアルでServiceの実装方法を確認することができました。サービスはコンポーネントと同じくAngularの基礎の一部なので、チュートリアルの内容をよく確認して、実装方法をマスターできればと思います。