※2016/1/25:このページはAngular 2 Beta 1を対象としています。以下のオンラインデモ、サンプルダウンロード、およびコードスニペットは、Angular 2 Beta 1と互換性があります。

Angular 2の取り組みを紹介します。WijmoチームはGoogleのAnuglarチームの協力を得て、Angular 2のリリースに合わせてWijmoコンポーネントを提供できるように開発を続けています。このページで紹介するWijmoのExplorerサンプルはAngular 2のコンセプトを学習できるサンプルになっています。

Angular 2対応のロードマップ

  • 現在:Angular 2 Explorerをリリース。Angular 2 サンプルはダウンロードしたフォルダの以下のディレクトリSamples\TS\Angular2トライアル版ダウンロード(Wijmo Enterprise)実行)に配置されています。
  • 2016/5:Angular 2のオフィシャルサポートコンポーネントをリリースします。

なぜAngular 2なのか?

Angular 1は、GoogleにおいてもWijmoにおいても成功を収めてきました。そして今、Angular 2のリリースに注目が高まっています。Angular 1とAngular 2は根本的に異なるものです。以下に、なぜAngular 2を検討すべきなのか、その主な理由を挙げます。

  • 最新トレンドであること。Angular 1の次のステップとしてAngular 2を検討するのは自然な流れです。コミュニティサポート、アップデート、機能強化を最も期待できるバージョンになります。
  • カプセル化が強化されています。コンポーネントは、ビューを含む再利用可能なTSクラスです。これらを任意の方法で組み合わせて、アプリケーションのビューやロジックを構築できます。
  • 高速な初期ロードやサーバー側の事前レンダリングによるパフォーマンスの向上、オフラインコンパイルによる高速起動、超高速な変更検知とビューキャッシングによるスムースな仮想スクロール、軽快なビュー遷移など、Angular 2はさまざまな機能が強化されています。
  • 多くのタスクをJavaScriptインタプリタ(およびTypeScriptトランスパイラ)に任せているため、Angular 1よりもシンプルになっています。そのため、HTML5プラットフォームをより効果的に活用できる軽量/高機能なアプリケーションを生成できます。
  • TypeScriptとの統合が強化されています。Angular 2とTypeScriptの併用は必須ではありませんが可能です。そうすることにより、強い型付け、コンパイル時エラーチェック、IntelliSenseサポートなどの大きなメリットを得られます。これはAngular 2自体がTypeScriptベースのコントロール(Wijmo 5コントロール等)だけでなく、アプリケーション全体をサポートします。

Wijmo 5によるAngular 2の実装

Angular 2用のWijmoコントロールExplorerサンプルは、ルーティング、カスタムサービス、パイプを備えた本格的なAngular 2 SPA(シングルページアプリケーション)です。ExplorerはAngular 2用のWijmoコンポーネントを使用しています。

Angular 2のExplorerサンプルは、Angular 1バージョンのExplorer(Wijmoライブラリ配布物に付属)に似ていますが、Angular 1バージョンの実装と比較することで、いくつかの重要な疑問に対する答えが見つかります。

  • Angular 1の機能をAngular 2でどのように実装するのか?
  • Angular 2アプリケーションマークアップ内のWijmoコントロールに対して、Angular 2のコンポーネントやディレクティブをどのように使用するのか?

サンプルとバージョンに関する注意事項

  • このサンプルはAngular 2 Beta 1に基づいています。
  • プラットフォームAPIは頻繁にバージョンアップされます。このサンプルとWijmoコントロールコンポーネントも継続的に更新する予定となっており常に最新バージョンに対応しています。
  • 当社は最新のAngular 2バージョンの適用に取り組んでいますが、現時点ではAngular 1のExplorerにあるすべてのサンプルページを追加しているわけではありません。
  • 現在のサンプルセットは、これまでに実装されたすべてのWijmoコントロールコンポーネントをカバーしています。すでに、以下のコアWijmoモジュール内のすべてのコントロールに対応するコンポーネントがあります。
    • wijmo
    • wijmo.input
    • wijmo.grid
    • wijmo.chart
    • wijmo.gauge
  • Wijmoコントロールコンポーネントの実装は包括的で次の機能をサポートします。
    • すべてのコントロールプロパティへの連結
    • プロパティへの双方向連結(InputNumberの”value”と”text”など、意味のある場合)
    • イベント連結
    • WjFlexGridColumnなどの子コンポーネントへのngForによる連結
  • サンプルは、Chrome、FireFox、Edgeなどの主要なデスクトップブラウザで動作することがテストされています。IEではAngular 2 Beta 1が機能しないことにご注意ください。(GoogleのAngularチームはこの問題を認識しており、Angularチームから修正バージョンがリリースされたら、直ちにサンプルを更新して対応する予定です。)

Angular 2とAngular 1のExplorerサンプルによる比較

Angular 2アプリケーション

Angular 1バージョンのExplorerサンプルでは、default.htmページのルート要素にng-app=appディレクティブを追加し、scripts/app.jsファイルでルートappアプリケーションモジュールを登録しました。default.htmのナビゲーション部分として、scripts/controllers/navigationCtrl.jsファイルで実装されているコントローラを参照するng-controller=navigationCtrlディレクティブもインクルードしました。

Angular 2バージョンの実装

default.htmページのbodyは次のようになります。

<body>
  <app-cmp></app-cmp>
</body>

<app-cmp>タグはルートアプリケーションコンポーネント、つまりアプリケーション全体を表します。サンプルのすべての動作はこのコンポーネント内で行われます。default.htmでは、このコンポーネントを追加してアプリケーションをブートストラップするためにのみ使用されます。Angular 2ではアプリケーション自身も、アプリケーションの各部(SPAビュー、Wijmoコントロールを表すコンポーネントなど)も、それぞれ1つのコンポーネントです。コンポーネントとは、モデル、コントローラ、ビューが一体となった単一のユニットと考えることができます。

コンポーネントとは、モデル、コントローラ、ビューが一体となった単一のユニットと考えることができます。

コンポーネントは2つのコアパーツから成ります。

  • TypeScriptクラス
    • .ts拡張子付きのファイルで実装されます。
    • モデルとコントローラを実装し、ビューで使用されるプロパティやイベントを公開します。
    • これはコンポーネントのビューのための”コードビハインド”です。
  • View(ビュー)
    • .htmlファイルで実装されます。
    • コンポーネントの外観を定義します。
    • ビューは他のコンポーネントを包含し、自コンポーネントのメンバーを他のコンポーネントのプロパティやイベントに連結できます。

<app-cmp>タグで表されるコンポーネントはsrc/app.tsファイルで実装され、そのビューは同じフォルダのsrc/app.htmlファイルで実装されます。

この実装のキーポイント。<app-cmp>には、サンプル内の他のコンポーネントと異なる点があります。<app-cmp>はアプリケーション全体を表します。したがって、ビューとビューのコードビハインドを提供するというコンポーネントの標準機能のほかに、次の追加機能を実装する必要があります。

  • SPAアプリケーション全体の外観を提供します。ナビゲーションメニューと、現在の”ページ”を表示すべき特別な場所が含まれます。これはAngular 1アプリケーションではng-viewディレクティブでマークされた要素に相当します。
  • アプリケーションルーティングを定義します。
  • アプリケーションをブートストラップします。

src/app.tsファイルではAppCmp TypeScriptクラスを定義しています。@Componentデコレータには”selector: ‘app-cmp'”定義があり、これは<app-cmp>タグをAppCmpクラスにマップします。Angularランタイムは、このタグに遭遇するとこのクラスのインスタンスを作成します。

Routing(ルーティング)

AppCmpクラスには@RouteConfigデコレータもあります。ここでアプリケーションのルーティングルールを定義します。これは、Angular 1 Explorerのapp.jsファイルにある”$routeProvider.when(…).when(…)…”のコードに相当します。Angular 1では、各ルート項目で仮想パスとコントローラを定義しました。ブラウザのアドレスフィールドに公開される仮想パスは、ng-viewディレクティブでマークされたタグに表示されるHTMLファイル(ビュー)のURLであり、コントローラは、このHTMLファイルを制御します。

Angular 2アプリケーションのルート項目定義の例を見てみましょう。

 { path: '/input/listbox', component: ListBoxCmp, as: 'InputListBox' },

ここでもルートは仮想パスとコンポーネントを定義しています。Angular 2ナビゲーションのターゲットはコンポーネント(この例ではListBoxCmpコンポーネント)であり、任意のHTMLファイルではありません。ユーザーがあるルート項目に関連付けられたリンクをクリックすると、Angular 2は次のように動作します。

  • そのルートに指定されたコンポーネントクラスのインスタンスを作成します。
  • そのビューを作成します。
  • アプリケーションビュー内の特別なタグにビューのDOMを追加します(このタグを定義する方法については後述)。

Navigation UI(ナビゲーションUI)

AppCmpコンポーネントのビューは、src/app.htmlファイルで定義されます。AppCmpクラスには、@Viewデコレータの”templateUrl: src/app.html“プロパティがあり、ここでコンポーネントのビューファイルのパスが定義されます。

このHTMLファイルはAngular 1 Explorerのdefault.htmファイルと内容はほぼ同じです。

ファイルの下部2行に注目すべきマークアップがあります。

<a [routerLink]="['/' + link.alias]">{{ link.text }}</a>

Angular 1では次の行に相当します。

<a ng-href="{{ link.url }}">{{ link.text }}</a>

Angular 2では、Angular 1のng-hrefディレクティブの代わりに、[routerLink]属性ディレクティブを使用します。このディレクティブには、Angular 1のようにルート仮想パスではなく、ルート名(エイリアス)を代入します。上のルート定義サンプルの場合、このようなエイリアスは、”as: InputListBox“プロパティを使用して指定されます。

重要なもう1つのマークアップは、Angularが現在のコンポーネントのビューを追加する場所となるタグです。Angular 1 Explorerでは、このタグをng-viewディレクティブでマークしました。Angular 2では、app.htmlファイルの下端にある<router-outlet></router-outlet>タグです。

Bootstrap(ブートストラップ)

app.tsファイルの最後は次のようになっています。

bootstrap(explorer.AppCmp, [
ROUTER_PROVIDERS,
provide(LocationStrategy, { useClass: HashLocationStrategy }),
MenuSvc,
DataSvc,
SparkSvc
]); 

このAngular bootstrapメソッドの呼び出しは、AppCmpコンポーネントのインスタンスを作成し、それをアプリケーションルートコンポーネントとして初期化します。つまり、アプリケーションを作成して実行するということです。

ここでは、さらにいくつかのパラメータを渡しています。

  • ルーティングがハッシュロケーションストラテジーを使用して機能するように指定します。つまり、ルートパスに続けてハッシュ記号(#)の後に仮想パスが追加されます。
  • MenuSvc、DataSvc、SparkSvcの各サービスを追加します。これらは、src/servicesフォルダで実装されている独自のカスタムサービスです。Angular 1 Explorerの同名のサービスに相当します。これらのサービスをbootstrapメソッド呼び出しで渡すことで、アプリケーション内のすべてのコンポーネントで利用できるようにしています。

コンポーネント実装内で何らかのサービスのインスタンスを取得するには、そのサービスタイプのパラメータをコンポーネントコンストラクタに追加するだけです。これで、Angularは、必要なサービスのインスタンスをこのパラメータに渡します。自分でインスタンスを作成する必要はありません。

たとえば、ListBoxCmpコンポーネントクラスのコンストラクタのシグネチャは、次のようになっています。

constructor( @Inject(DataSvc) dataSvc: DataSvc) 

ここではDataSvcサービスタイプのパラメータを定義しています。このパラメータは、DataSvcサービスのインスタンスを受け取り、コンストラクタコード内ですぐに使用できるようになります。サービスが通常のTypeScriptクラスとして実装されることを言及しておきます。

フォルダ構成

Explorerサンプルは次のフォルダで構成されます。

  • “scripts”フォルダ
    • サブフォルダ
      • wijmo.angular2:Angular 2 Wijmoコントロールコンポーネントの実装が含まれます。
  • “src”フォルダ
    • アプリケーションコンポーネント、サービス、パイプのすべてが実装されます。
    • サブフォルダ
      • components:Explorerサンプルの各”ページ”を表すコンポーネントの実装が含まれます。
      • inputgridchartなどのサブフォルダ:特定のWijmoモジュールに関連する実装が含まれます。
      • 各コンポーネントは1つのサンプルを表します。たとえば、gridサブフォルダ内のGridIntroCmpコンポーネントとGridGroupingCmpコンポーネントは、FlexGridの”Introduction”サンプルと”Grouping”サンプルを表します。
      • 各コンポーネントの実装は、同じフォルダ内の2つのファイルで表されます。
        • .ts fileはコンポーネントクラスとデコレーションを定義します。
        • .html fileはコンポーネントビューを定義します。
        • 例:GridIntroCmp.tsおよびgridIntroCmp.html
    • 対応するAngular 1 Explorerのコードは、scripts/controllersフォルダとpartialsフォルダにあります。ここにはそれぞれ、JavaScriptコントローラとHTMLビューの実装が含まれます。
  • “services”サブフォルダには、アプリケーションサービスを実装するTypeScriptクラスが含まれます。これは、”scripts/services”フォルダで実装されるAngular 1 Explorerサービスに相当します。
  • “pipes”サブフォルダはカスタム”パイプ”を実装します。Angular 2のパイプはAngular 1のフィルタに当たり、同じように使用されます。これに対応するAngular 1 Explorerのフォルダは”scripts/filters”です。
  • resources“フォルダと”translations“フォルダの意味はAngular 1 Explorerと同じで、内容も同じです。

Wijmoコントロールのコンポーネント

Wijmoコントロールのコンポーネントは、scripts/wijmo.angular2フォルダで実装されています。各Wijmoモジュールのコンポーネントセットは、個別に外部TypeScriptモジュールで実装されます(例:wijmo.angular2.input.tswijmo.angular2.grid.ts)。

便宜的にwijmo.angular2.all.tsモジュールも用意されています。これは、他のWijmoコンポーネントモジュールをすべてエクスポートするモジュールです。Wijmoコンポーネントを使用するAngular 2コンポーネントを記述する場合は、すべてのWijmoコンポーネントがインポートされたwijmo.angular2.all.tsをインポートすることをお勧めします。

このモジュールは、コンポーネントモジュールごとに1つのシンボルをエクスポートしています。シンボルは、”wjNg2“の後にモジュール名が続きます。たとえば、wjNg2InputとwjNg2Gridはそれぞれ、InputおよびFlexGridコントロールコンポーネントを含むモジュールのシンボルです。

次に、このモジュールからシンボルをインポートする例を示します。

import { wjNg2Input, wjNg2Grid } from '../../../scripts/wijmo.angular2/wijmo.angular2.all';

これで、wjNg2Input.WjMenuwjNg2Grid.WjFlexGridのような式を使用して、コンポーネントクラスを参照できます。

WijmoコントロールのAngular 2コンポーネントをHTMLマークアップで使用する方法は、Angular 1とほとんど同じです。たとえば、次のマークアップは、いくつかの項目を含むWijmo Menuを作成します。

<wj-menu [(value)]="itemCount"
[header]="'Items'"
(itemClicked)="menuItemClicked(menu3, $event)">
<wj-menu-item [value]="5">5</wj-menu-item>
<wj-menu-item [value]="50">50</wj-menu-item>
<wj-menu-item [value]="500">500</wj-menu-item>
</wj-menu>

Angular 1と異なる点はプロパティ連結の構文だけです。Angular 2では、以下のようにプロパティ名をかっこで囲む必要があります。

  • 単方向連結:角かっこ
    • 例:[header]
  • イベント連結:丸かっこ
    • 例:(itemClicked)
  • 双方向連結:角かっこと丸かっこ
    • 例:[(value)]

Wijmoコントロールのコンポーネントは、それが表すコントロールクラスから直接派生されます。InputNumberコントロールを表すコンポーネントクラスの定義は、次のようになります。

export class WjInputNumber extends wijmo.input.InputNumber

したがって、コントロールコンポーネントインスタンスの参照を取得したら、自動的にコントロール自身の参照を取得したことになり、そのAPIを使用できるようになります。コンポーネントの参照は、ローカルテンプレート変数を介して通常の方法で取得できます。たとえば、次のマークアップは、FlexGridインスタンスを参照する”flex”変数を提供します。

<wj-flex-grid #flex [itemsSource]="data"></wj-flex-grid>

コンポーネントの実装

コンポーネントの実装から、注目すべき点を紹介します。

複数のビューに1つのコントローラ

Angular 1では、ビューとコントローラを別々に定義し、それらを任意の方法で組み合わせることが自由にできます。HTMLページ内の任意の部分を特定のコントローラに連結するように宣言することも、同じコントローラを複数のHTMLページで使用することさえ可能です。Angular 1 Explorerはこの機能を幅広く利用しています。たとえば、このサンプルでは、basicCtrlコントローラを定義して多数のFlexGridサンプルページ(intro.htm、grouping.htm、paging.htmなど)で使用しています。

Angular 2ではコンポーネントでモデル/コントローラロジックとビューの両方を一体として定義します。それらを別々に定義し、必要に応じて組み合わせることはできません。

TypeScriptクラスの継承機能を利用することでこの問題を解決します。基本クラスで実装された共通のモデル/コントローラロジックを使用しつつ、派生クラスで特定のビューを実装します。複数の派生クラスから提供される複数のビューで、基本クラスにある同じモデル/コントローラ実装を継承できます。

FlexGridサンプルを表すコンポーネントのクラス定義を見てみます。

export class GridIntroCmp extends GridBaseCmp
export class GridGroupingCmp extends GridBaseCmp

Grid IntroductionサンプルとGroupingサンプルを表す2つのコンポーネントクラスが同じGridBaseCmpクラスから派生されています。

基本GridBaseCmpクラスは次の機能を持ちます。

  • すべてのモデル/コントローラ動作を実装します。
  • ビューの連結に必要なすべてのプロパティを公開します。
  • ビューイベントから呼び出されるすべてのメソッドを公開します。

基本クラスがあれば、(GridGroupingCmpなどの)コンポーネントクラスを派生でき、コントローラの動作とAPIは自動的に基本GridBaseCmpクラスから継承されます。これは、複数のビューで1つのコントローラを使用していたAngular 1と本質的に同じことです。

コンポーネントからコントロールの参照を取得する

コンポーネントのビューで定義されているコントロールを参照しなければならないことがあります。Angular 1では、Wijmoディレクティブのcontrolプロパティをコントローラプロパティに連結することで参照を取得できます。Angular 2では、ビューでコントロールのコンポーネント要素に”ローカルテンプレート変数”を追加する必要があります。

たとえば、GridIntroCMPコンポーネントのビューで、FlexGridに使用する”flex”テンプレート変数を定義します。

<wj-flex-grid #flex …>

コンポーネントコードでは次の変数を宣言します。これは、マークアップで定義された#flex変数を使用して、自動的にFlexGridインスタンスの参照を取得します。

// ビューで'flex'という名前のFlexGridを参照します
@ViewChild('flex') flex: wijmo.grid.FlexGrid;

この宣言はGridBaseCmpクラス(GridIntroCmpの基本クラス)にあるにもかかわらず、GridIntroCmpビューで定義された参照を受け取ることに注意してください。

コンポーネントプロパティの変化への応答

コントローラプロパティの変化に対して何らかのアクションを行う必要がある場合、Angular 1では、$scope.$watch関数を使用してコールバックを記述します。プロパティ値が変化すると、そのコールバックが呼び出されます。Angular 2では、ゲッターとセッターを持つES5プロパティを宣言し、そのプロパティセッターで必要なアクションを行うだけです。

たとえば、次の宣言は、GridBaseCmpクラスにdataMaps;プロパティを定義し、プロパティが変化したときに_updateDataMapsメソッドを呼び出します。

get dataMaps(): boolean {
return this._dataMaps;
}
set dataMaps(value: boolean) {
if (this._dataMaps != value) {
this._dataMaps = value;
this._updateDataMaps();
}
}

プロパティの変化に応答するもう1つの方法にコンポーネントクラスに対してonChangesメソッドを追加する方法もあります。Angularは、プロパティが変化するたびに自動的にこのメソッドを呼び出します。

Services(サービス)

サービスは、いくつかのメソッドまたはプロパティを公開する任意のクラスです。クラスを@Injectable()デコレータでマークすることで、そのサービスをAngularがコンポーネントにインジェクトできるようになります。

たとえば、DataSvcサービスの定義は次のようになります。

@Injectable()
export class DataSvc {

これをコンポーネントにインジェクトするには、@Injectデコレータを付けて、サービスをコンポーネントコンストラクタのパラメータとして指定します。

constructor( @Inject(DataSvc) dataSvc: DataSvc) {

Pipes(パイプ)

パイプはAngular 1のフィルタに相当します。パイプは、変換メソッドを公開する@Pipeデコレータ付きのクラスとして実装されます。

たとえば、Angular 1 Explorerのglbzフィルタに対応する”glbz”パイプは、次のように実装されます。

@Pipe({
name: 'glbz',
// 状態を持つパイプ
pure: false
})
export class GlbzPipe {
transform(value: any, args: string[]): any {
return wijmo.Globalize.format(value, args[0]);
}
}

次のように使用します。

{{passengers | glbz:'n0'}}

Angular 2に対応したWijmoサンプルのダウンロード