🐣

Angularの公式チュートリアルをやっていく その10 - Angular services

2023/06/17に公開

Angularの公式チュートリアル「はじめての Angularアプリ」を進めていきます。

一覧
Angularの公式チュートリアルをやっていく その1 - Introduction
Angularの公式チュートリアルをやっていく その2 - Hello world
Angularの公式チュートリアルをやっていく その3 - Create home component
Angularの公式チュートリアルをやっていく その4 - Create housing location component
Angularの公式チュートリアルをやっていく その5 - Create an interface
Angularの公式チュートリアルをやっていく その6 - Add inputs to components
Angularの公式チュートリアルをやっていく その7 - Add property binding to components
Angularの公式チュートリアルをやっていく その8 - Add dynamic values to templates
Angularの公式チュートリアルをやっていく その9 - Use *ngFor in templates
Angularの公式チュートリアルをやっていく その10 - Angular services
Angularの公式チュートリアルをやっていく その11 - Add routing
Angularの公式チュートリアルをやっていく その12 - Customize the details page
Angularの公式チュートリアルをやっていく その13 - Integrate Angular forms
Angularの公式チュートリアルをやっていく その14 - Add search functionality
Angularの公式チュートリアルをやっていく その15 - Add HTTP communication

今回やるのは、↓の部分です。

https://angular.jp/tutorial/first-app/first-app-lesson-09

Angularサービスと依存性注入

このページで使うのは、Angularサービス依存性注入という二つの機能です。

ページに記述されている英文の和訳と解説を書いたのでご確認ください。

Angularサービス(Angular services)

Angularのサービスは、あなたのAngularアプリケーションのデータと機能を分離する方法を提供します。これにより、同じ機能を複数のコンポーネントで再利用できます。複数のコンポーネントで使用されるためには、サービスを「Injectable」つまり注入可能にする必要があります。注入可能にされたサービスは、それを使用するコンポーネントの依存性となります。つまり、コンポーネントはそのサービスに依存し、そのサービスがないと機能しないという関係になります。
和訳 - https://angular.jp/tutorial/first-app/first-app-lesson-09#angular-services

サービスは通常、データフェッチ、バックエンドAPIとの通信、一部の計算、非同期操作など、アプリケーションのビジネスロジックを担当します。

サービスの利点は、これらのタスクを独立した単位として分離することで、再利用性とテストの容易性を向上させることができる点にあります。

依存性注入(Dependency injection)

依存性注入は、アプリケーションのコンポーネントとその他のコンポーネントが使用できるサービスの依存性を管理するメカニズムです。依存性注入は、特定のクラスが必要とする他のクラス(依存性)を動的に提供します。これにより、コンポーネントは自身が必要とするサービスの実体化やライフサイクル管理を行う必要がなくなります。
和訳 - https://angular.jp/tutorial/first-app/first-app-lesson-09#dependency-injection

Angularの依存性注入は、あるサービスが必要な場合にそのサービスを自動的に注入(提供)します。

これにより、アプリケーションのコードはよりモジュラーで、再利用可能で、テストしやすくなります。

それぞれのコンポーネントやサービスはそれ自体のタスクに集中でき、他のクラスのインスタンス化について心配する必要がありません。依存性注入システムがこれを取り扱ってくれます。

新しいサービスの作成

これらを踏まえたうえで、アプリケーションに新しいサービスを作成します。

下記のコマンドを実行します。

ng generate service housing --skip-tests


新しいファイルが生成されました。

まだ、実装は空の状態です。

housing.service.ts
import { Injectable } from '@angular/core';

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

  constructor() { }
}


アプリケーションを一度ビルドして、生成に不具合がないか確かめます。

ng serve


ここで上手くビルドできずエラーとなってしまったら、サービスファイルhousing.service.tsの生成が上手くいっていない可能性がありますので、一度生成されたファイルを消して再度生成するか、エラー文を読んで対処しましょう。

新しいサービスに静的(static)データを追加する

housing.service.tsにコードを追加していきます。

HomeComponent から housingLocationList 変数とその配列値をコピーする

home.component.tsのHomeComponentクラスのフィールドhousingLocationListを全て、housing.service.tsHousingServiceクラスにコピーしましょう。

housing.service.ts
  import { Injectable } from '@angular/core';
+ import { HousingLocation } from './housinglocation';
  
  @Injectable({
    providedIn: 'root'
  })
  export class HousingService {
  
+   housingLocationList: HousingLocation[] = [
+     {
+       id: 0,
+       name: 'Acme Fresh Start Housing',
+       city: 'Chicago',
+       state: 'IL',
+       photo: '/assets/bernard-hermant-CLKGGwIBTaY-unsplash.jpg',
+       availableUnits: 4,
+       wifi: true,
+       laundry: true,
+     },
+     {
+       id: 1,
+       name: 'A113 Transitional Housing',
+       city: 'Santa Monica',
+       state: 'CA',
+       photo: '/assets/brandon-griggs-wR11KBaB86U-unsplash.jpg',
+       availableUnits: 0,
+       wifi: false,
+       laundry: true,
+     },
+     {
+       id: 2,
+       name: 'Warm Beds Housing Support',
+       city: 'Juneau',
+       state: 'AK',
+       photo: '/assets/i-do-nothing-but-love-lAyXdl1-Wmc-unsplash.jpg',
+       availableUnits: 1,
+       wifi: false,
+       laundry: false,
+     },
+     {
+       id: 3,
+       name: 'Homesteady Housing',
+       city: 'Chicago',
+       state: 'IL',
+       photo: '/assets/ian-macdonald-W8z6aiwfi1E-unsplash.jpg',
+       availableUnits: 1,
+       wifi: true,
+       laundry: false,
+     },
+     {
+       id: 4,
+       name: 'Happy Homes Group',
+       city: 'Gary',
+       state: 'IN',
+       photo: '/assets/krzysztof-hepner-978RAXoXnH4-unsplash.jpg',
+       availableUnits: 1,
+       wifi: true,
+       laundry: false,
+     },
+     {
+       id: 5,
+       name: 'Hopeful Apartment Group',
+       city: 'Oakland',
+       state: 'CA',
+       photo: '/assets/r-architecture-JvQ0Q5IkeMM-unsplash.jpg',
+       availableUnits: 2,
+       wifi: true,
+       laundry: true,
+     },
+     {
+       id: 6,
+       name: 'Seriously Safe Towns',
+       city: 'Oakland',
+       state: 'CA',
+       photo: '/assets/phil-hearing-IYfp2Ixe9nM-unsplash.jpg',
+       availableUnits: 5,
+       wifi: true,
+       laundry: true,
+     },
+     {
+       id: 7,
+       name: 'Hopeful Housing Solutions',
+       city: 'Oakland',
+       state: 'CA',
+       photo: '/assets/r-architecture-GGupkreKwxA-unsplash.jpg',
+       availableUnits: 2,
+       wifi: true,
+       laundry: true,
+     },
+     {
+       id: 8,
+       name: 'Seriously Safe Towns',
+       city: 'Oakland',
+       state: 'CA',
+       photo: '/assets/saru-robert-9rP3mxf8qWI-unsplash.jpg',
+       availableUnits: 10,
+       wifi: false,
+       laundry: false,
+     },
+     {
+       id: 9,
+       name: 'Capital Safe Towns',
+       city: 'Portland',
+       state: 'OR',
+       photo: '/assets/webaliser-_TPTXZd9mOo-unsplash.jpg',
+       availableUnits: 6,
+       wifi: true,
+       laundry: true,
+     },
+   ];
  
    constructor() { }
  }


HousingServiceにGetterメソッドを追加する

housing.service.tsファイルのHousingServiceクラスにメソッドを追加します。
追加するメソッドはgetAllHousingLocationsgetHousingLocationByIdそれぞれ以下の機能を持ちます。

  • getAllHousingLocations
    housingLocationListに格納されている家データ全てを取得するメソッド。
    家データをオブジェクト配列として取得できる。

  • getHousingLocationById
    housingLocationListから、指定したIDの家データのみを取得するメソッド。
    家データを一つだけオブジェクトとして取得できる。

以下の通りにコードを追加しましょう。

housing.service.ts
  import { Injectable } from '@angular/core';
  import { HousingLocation } from './housinglocation';
  
  @Injectable({
    providedIn: 'root',
  })
  export class HousingService {
    housingLocationList: HousingLocation[] = [
      {
        id: 0,
        name: 'Acme Fresh Start Housing',
        city: 'Chicago',
        state: 'IL',
        photo: '/assets/bernard-hermant-CLKGGwIBTaY-unsplash.jpg',
        availableUnits: 4,
        wifi: true,
        laundry: true,
      },
      {
        id: 1,
        name: 'A113 Transitional Housing',
        city: 'Santa Monica',
        state: 'CA',
        photo: '/assets/brandon-griggs-wR11KBaB86U-unsplash.jpg',
        availableUnits: 0,
        wifi: false,
        laundry: true,
      },
      {
        id: 2,
        name: 'Warm Beds Housing Support',
        city: 'Juneau',
        state: 'AK',
        photo: '/assets/i-do-nothing-but-love-lAyXdl1-Wmc-unsplash.jpg',
        availableUnits: 1,
        wifi: false,
        laundry: false,
      },
      {
        id: 3,
        name: 'Homesteady Housing',
        city: 'Chicago',
        state: 'IL',
        photo: '/assets/ian-macdonald-W8z6aiwfi1E-unsplash.jpg',
        availableUnits: 1,
        wifi: true,
        laundry: false,
      },
      {
        id: 4,
        name: 'Happy Homes Group',
        city: 'Gary',
        state: 'IN',
        photo: '/assets/krzysztof-hepner-978RAXoXnH4-unsplash.jpg',
        availableUnits: 1,
        wifi: true,
        laundry: false,
      },
      {
        id: 5,
        name: 'Hopeful Apartment Group',
        city: 'Oakland',
        state: 'CA',
        photo: '/assets/r-architecture-JvQ0Q5IkeMM-unsplash.jpg',
        availableUnits: 2,
        wifi: true,
        laundry: true,
      },
      {
        id: 6,
        name: 'Seriously Safe Towns',
        city: 'Oakland',
        state: 'CA',
        photo: '/assets/phil-hearing-IYfp2Ixe9nM-unsplash.jpg',
        availableUnits: 5,
        wifi: true,
        laundry: true,
      },
      {
        id: 7,
        name: 'Hopeful Housing Solutions',
        city: 'Oakland',
        state: 'CA',
        photo: '/assets/r-architecture-GGupkreKwxA-unsplash.jpg',
        availableUnits: 2,
        wifi: true,
        laundry: true,
      },
      {
        id: 8,
        name: 'Seriously Safe Towns',
        city: 'Oakland',
        state: 'CA',
        photo: '/assets/saru-robert-9rP3mxf8qWI-unsplash.jpg',
        availableUnits: 10,
        wifi: false,
        laundry: false,
      },
      {
        id: 9,
        name: 'Capital Safe Towns',
        city: 'Portland',
        state: 'OR',
        photo: '/assets/webaliser-_TPTXZd9mOo-unsplash.jpg',
        availableUnits: 6,
        wifi: true,
        laundry: true,
      },
    ];
  
    constructor() {}
    
+   getAllHousingLocations(): HousingLocation[] {
+     return this.housingLocationList;
+   }
+
+   getHousingLocationById(id: number): HousingLocation | undefined {
+     return this.housingLocationList.find(housingLocation => housingLocation.id === id);
+   }
  }


いつもの如く、アプリケーションを再ビルドして、エラーがないか確かめます。

ng serve


ここでエラーが出てブラウザの表示が上手くいかなかったら、コードの追加が上手くいっていない可能性が高いので、確かめてください。

HomeComponentに新しいサービスを注入する

先程housing.service.tsに家データをコピーしたので、画面表示にはこのデータを使うようにコードを修正します。

具体的には、次のステップです。

  1. home.component.tsHomeComponentクラスからhousingLocationListフィールドを削除する
  2. 依存性注入を使って、housing.service.tsのデータをhome.component.tsに持ってくる

以下のようにコードを変更します。

home.component.ts
- import { Component } from '@angular/core';
+ import { Component, inject } from '@angular/core';
  import { CommonModule } from '@angular/common';
  import { HousingLocationComponent } from '../housing-location/housing-location.component';
  import { HousingLocation } from '../housinglocation';
+ import { HousingService } from '../housing.service';
  
  @Component({
    selector: 'app-home',
    standalone: true,
    imports: [CommonModule, HousingLocationComponent],
    template: `
      <section>
        <form>
          <input type="text" placeholder="Filter by city" />
          <button class="primary" type="button">Search</button>
        </form>
      </section>
      <section class="results">
        <app-housing-location
          *ngFor="let housingLocation of housingLocationList"
          [housingLocation]="housingLocation"
        ></app-housing-location>
      </section>
    `,
    styleUrls: ['./home.component.css'],
  })
  export class HomeComponent {
+   housingLocationList: HousingLocation[] = [];
+   
+   housingService: HousingService = inject(HousingService);

+   constructor() {
+     this.housingLocationList = this.housingService.getAllHousingLocations();
+   }
+   
-   housingLocationList: HousingLocation[] = [
-     {
-       id: 0,
-       name: 'Acme Fresh Start Housing',
-       city: 'Chicago',
-       state: 'IL',
-       photo: '/assets/bernard-hermant-CLKGGwIBTaY-unsplash.jpg',
-       availableUnits: 4,
-       wifi: true,
-       laundry: true,
-     },
-     {
-       id: 1,
-       name: 'A113 Transitional Housing',
-       city: 'Santa Monica',
-       state: 'CA',
-       photo: '/assets/brandon-griggs-wR11KBaB86U-unsplash.jpg',
-       availableUnits: 0,
-       wifi: false,
-       laundry: true,
-     },
-     {
-       id: 2,
-       name: 'Warm Beds Housing Support',
-       city: 'Juneau',
-       state: 'AK',
-       photo: '/assets/i-do-nothing-but-love-lAyXdl1-Wmc-unsplash.jpg',
-       availableUnits: 1,
-       wifi: false,
-       laundry: false,
-     },
-     {
-       id: 3,
-       name: 'Homesteady Housing',
-       city: 'Chicago',
-       state: 'IL',
-       photo: '/assets/ian-macdonald-W8z6aiwfi1E-unsplash.jpg',
-       availableUnits: 1,
-       wifi: true,
-       laundry: false,
-     },
-     {
-       id: 4,
-       name: 'Happy Homes Group',
-       city: 'Gary',
-       state: 'IN',
-       photo: '/assets/krzysztof-hepner-978RAXoXnH4-unsplash.jpg',
-       availableUnits: 1,
-       wifi: true,
-       laundry: false,
-     },
-     {
-       id: 5,
-       name: 'Hopeful Apartment Group',
-       city: 'Oakland',
-       state: 'CA',
-       photo: '/assets/r-architecture-JvQ0Q5IkeMM-unsplash.jpg',
-       availableUnits: 2,
-       wifi: true,
-       laundry: true,
-     },
-     {
-       id: 6,
-       name: 'Seriously Safe Towns',
-       city: 'Oakland',
-       state: 'CA',
-       photo: '/assets/phil-hearing-IYfp2Ixe9nM-unsplash.jpg',
-       availableUnits: 5,
-       wifi: true,
-       laundry: true,
-     },
-     {
-       id: 7,
-       name: 'Hopeful Housing Solutions',
-       city: 'Oakland',
-       state: 'CA',
-       photo: '/assets/r-architecture-GGupkreKwxA-unsplash.jpg',
-       availableUnits: 2,
-       wifi: true,
-       laundry: true,
-     },
-     {
-       id: 8,
-       name: 'Seriously Safe Towns',
-       city: 'Oakland',
-       state: 'CA',
-       photo: '/assets/saru-robert-9rP3mxf8qWI-unsplash.jpg',
-       availableUnits: 10,
-       wifi: false,
-       laundry: false,
-     },
-     {
-       id: 9,
-       name: 'Capital Safe Towns',
-       city: 'Portland',
-       state: 'OR',
-       photo: '/assets/webaliser-_TPTXZd9mOo-unsplash.jpg',
-       availableUnits: 6,
-       wifi: true,
-       laundry: true,
-     },
-   ];
  }


コードを上記のように変更することで、これまでHomeComponentクラスに直書きしていた家データを他のファイル(今回の場合はhome.component.ts)に移すことに成功しました。

こうすることで、コンポーネントファイル(今回の場合はhome.component.ts)は画面表示だけを目的としたコードしか記述されず、スッキリとした見た目になりましたね。

画面表示も、勿論そのままです。


画面表示変化しなかったり、エラーが起きて上手くいかない場合は、次のことが考えられます。

  • 変更したファイルを保存していない
  • 変更したコードが間違っている
  • 変更箇所以外のコードも間違って削除してしまった

何か間違いがないか、今一度確認してみましょう。

これにてAngular servicesは完了です。


← 前へ Angularの公式チュートリアルをやっていく その9 - Use *ngFor in templates
→ 次へ Angularの公式チュートリアルをやっていく その11 - Add routing

Discussion