Angularチュートリアルその4 一覧と詳細のコンポーネントの分割

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

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

今まではHeroコンポーネントだけで一覧の表示と編集を行なっていましたが、それを一覧のコンポーネント(Master)と詳細のコンポーネント(Detail)に分割します。

このチュートリアルがマスターできれば、機能分割されたシンプルなコンポーネントの実装が行えるようになります。

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

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

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

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

開発環境

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

HeroDetailComponentの作成

下記コマンドを実行して、hero-detailコンポーネントを作成します。

$ ng generate component hero-detail

コマンドを実行すると、HeroDetailComponentが生成され、AppModuleにも宣言情報が追記されます。

テンプレート実装

詳細部分のテンプレートを実装します。

コンポーネントを追加した際に、hero-detail.component.htmlというファイルも追加されているので、そのファイルを編集していきます。

<div *ngIf="hero">

  <h2>{{ hero.name | uppercase }} Details</h2>
  <div><span>id: </span>{{hero.id}}</div>
  <div>
    <label>name:
      <input [(ngModel)]="hero.name" placeholder="name"/>
    </label>
  </div>

</div>

hero propertyをInputデコレータとして追加する

HeroDetailComponentのテンプレートはHeroという型のプロパティをバインドしています。HeroDetailComponentHeroというシンボルをインポートします。

import { Hero } from '../hero';

次に、今まで詳細部分のテンプレートの実装を行なっていた「heroes.component.html」の詳細表示を、HeroDetailComponentが実行されるように変更します。

<app-hero-detail [hero]="selectedHero"></app-hero-detail>

hero-detail.component.ts の@angular/coreのインポート文の所にInputを追加します。

import { Component, OnInit, Input } from '@angular/core';

最後に@Input()デコレータとしてheroプロパティをhero-detail.component.tsに追加します。

export class HeroDetailComponent implements OnInit {
  @Input() hero: Hero;

  constructor() { }

  ngOnInit() {
  }

}

HeroDetailComponentを表示する

今のままではまだ詳細部分の表示はできないので、HeroDetailComponentが実行されるように、HeroesComponent周りを修正していきます。

HeroesComponentの修正

heroes.component.htmlを修正します。

<app-hero-detail [hero]="selectedHero"></app-hero-detail>

このように修正することで、HeroDetailをバインドするようになります。

heroes.component.htmlは最終的にこのようになります。

<h2>My Heroes</h2>

<ul class="heroes">
  <li *ngFor="let hero of heroes"
    [class.selected]="hero === selectedHero"
    (click)="onSelect(hero)">
    <span class="badge">{{hero.id}}</span> {{hero.name}}
  </li>
</ul>

<app-hero-detail [hero]="selectedHero"></app-hero-detail>

前回からの変更点

前回の1つのコンポーネントによる実装から2つのコンポーネントにしたことによる変更点は下記の通りです。

  1. HeroesComponentの影響範囲を小さくして、簡略化を行なった。
  2. HeroesComponentを編集しなくてもHeroDetailComponentを使って詳細部分のカスタマイズができるようになった。
  3. 詳細部分を意識することなく、一覧のカスタマイズができるようになった。
  4. 機能を分割したことで詳細部分を再利用することができるようになった。

機能分割を行うことでそれぞれの機能が分離されるため、コード変更時の影響範囲を軽減させながら、機能拡張性を高めることができました!

ソースコードについて

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

最後に

今回のチュートリアルでコンポーネントの分割方法を理解することができました。コンポーネントを分割することで、作業分担も簡単になったり、コンポーネントの再利用性を高めることができるようになると思います。

また、コードのスパゲッティ化も防ぐこともできると思います。

ただ、あまりコンポーネントを分割しすぎても、管理やバインディングが煩雑になるので、どのサイズでコンポーネントを切り分けるかはプロジェクトの規模などに応じて決めていく必要があると思います。