はじめに
Angular 2はGoogleとオープンソースコミュニティで開発されているJavaScriptフレームワークで、従来のAngularJS(AngularJS 1)の次期バージョンです。2016年9月に正式版がリリースされ、本格的に利用できる環境が整いました。Angular 2はAngularJS 1に対して多くの変更点があり、コードの記述法も基本的に異なります。
前回記事では、Angular 2のWebページを構成する要素である、コンポーネントやモジュールについて説明しました。これらを利用すると、実装を分割して互いの影響範囲を限定することができます。
しかし、ログ出力のようにさまざまな箇所で使われる処理や、ビジネスロジックのような画面から独立した処理は、独立して実装した処理を、後から追加できれば便利です。Angular 2ではこのような機能として、独立した処理を実装する「サービス」と、サービスをコンポーネントやモジュールに後から追加する「依存性注入(Dependency Injection)」が利用できます。
本記事では、まず前回記事で説明しきれなかったモジュール化の方法について、サンプルをあげて説明します。次にそのサンプルへ共通処理を追加していくことで、サービスと依存性注入の利用法を解説します。
対象読者
- 正式版になったので本格的にAngular 2を使い始めようと思っている方
- 最新フレームワークに触れておきたい方
- 作成したソースコードを部品化・再利用したい方
必要な環境
Angular 2はJavaScriptのフレームワークですが、公式WebサイトのドキュメントやサンプルはTypeScript向けが先行して整備される場合が多く、本連載でもTypeScriptでコードを記述していきます。また、サンプルの実行にはNode.jsが必要になります。
今回は以下の環境で動作を確認しています。
-
Windows 10 64bit版
- Angular 2 2.1.0
- Node.js v6.8.0 64bit版
- Microsoft Edge 38.14393.0.0
Angular 2の公式Webサイトでは基本的なAngular 2の実行環境を整える手順をQUICKSTARTとして公開しており、本記事のサンプルコードも、クイックスタートで作成したファイル一式をベースにします。2016年10月現在の手順で作成したクイックスタートプロジェクト(angular-quickstart)を、ダウンロードできるサンプルコードに含めています。プロジェクトの実行方法については過去記事も参照してください。
自作したコンポーネントをモジュールに切り出し
前回記事のサンプル(angular2-003-component3)では、リストの詳細を表示する詳細表示コンポーネントと、リストに項目を追加する項目追加コンポーネントを実装して、ルートコンポーネントの配下に追加する実装例を説明しました(図1)。しかしモジュールという観点で見た場合、これらのコンポーネントはすべて最上位のルートモジュール(AppModule)に含まれており、モジュール分割されていない状態です。ここまでの内容については前回記事も参照してください。
今回はここから一歩進めて、詳細表示コンポーネントと項目追加コンポーネントを別のモジュールに切り出す方法を紹介します。まずappフォルダにサブフォルダphoneutilを作成して、関連するファイル(phonedetail.component.ts、phoneinput.component.ts、phone.ts)を移動します。さらにphoneutilフォルダーに追加モジュールの定義ファイルをリスト1のように作成します。
// モジュール参照 ...(1) import { NgModule } from "@angular/core"; import { BrowserModule } from "@angular/platform-browser"; import { FormsModule } from "@angular/forms"; // コンポーネント参照 ...(2) import { PhoneDetailComponent } from "./phonedetail.component"; import { PhoneInputComponent } from "./phoneinput.component"; // モジュールのメタデータ定義 ...(3) @NgModule({ imports: [ BrowserModule, FormsModule ], declarations: [ PhoneDetailComponent, PhoneInputComponent ], exports: [ PhoneDetailComponent, PhoneInputComponent ] }) // モジュールクラス定義 export class PhoneUtilModule { }
(1)で使用するAngular 2のモジュール、(2)でモジュールに含むコンポーネントを参照します。(3)のメタデータ定義は「(imports属性で)このモジュールではBrowserModuleとFormsModuleを利用して」、「(declarations属性で)このモジュールにはPhoneDetailComponentとPhoneInputComponentを含み」、「(exports属性で)このモジュールからPhoneDetailComponentとPhoneInputComponentを外部に公開する」という指定を行っています。exports属性は、モジュールが外部に公開するコンポーネントの指定に利用します。
ルートモジュール側ではリスト2のように、コンポーネント個別ではなく、追加されたモジュールPhoneUtilModuleを参照するように修正します。PhoneUtilModuleを参照すると、リスト1のexports属性で指定したコンポーネントが、ルートモジュールで利用できるようになります。
import { PhoneUtilModule } from "./phoneutil/phoneutil.module"; ... @NgModule({ imports: [ BrowserModule, PhoneUtilModule ], ... })
リスト1、2でモジュール分割しても、モジュール分割前(図1)と変わらず動作します。