目次


Polymer を使用して再利用可能なカスタム Web コンポーネントを作成する

Comments

Polymer を導入して Web Components による革命に参加する」では、W3C Web Components 標準とそのサポート・テクノロジーを紹介し、Polymer のコア・コンポーネントを (さらに他のコミュニティー Web コンポーネントも) 組み合わせて、簡単にレスポンシブで実用的なアプリケーション UI を作成する方法を紹介しました。コンポーネントの利用者としての開発者の役割は、そのチュートリアルの例で十分に説明しました。

今回のチュートリアルでは、Polymer コンポーネントの作成者としての役割に注目します。つまり、コミュニティーのリポジトリーで共有する目的、あるいは独自のアプリケーションに組み込む目的で、組み合わせて再利用することが可能なビルド済みの Web コンポーネントを作成する開発者の役割です。ここではサンプルとして、<national-sales-explorer> カスタム Web コンポーネントを作成する手順を紹介します。このコンポーネントには、以下の機能がカプセル化されます。

  • UI 処理
  • ネットワーク・データ・ソースからの情報の取得
  • ビジネス・グラフを使用した売上データの表示
  • インタラクティブ・マップでの店舗位置情報の表示

この手順の中で説明する、Polymer コンポーネントのいくつかの組み立て手法は、皆さんの作業に役立つはずです。

この手順では、Bluemix 上の Mobile Cloud ボイラープレートを使用し、REST API エンドポイントをホストするためと、アプリケーションをデプロイするために Bluemix を利用します。ソース・コードは IBM DevOps Services に用意されているので、お望みであれば、すべての作業をクラウド内で行うことができます。

必要となるもの

  • IBM ID とパスワード
  • Bluemix と IBM DevOps Services のアカウント
  • 最近の Web ブラウザー (Chrome を推奨)
  • (ローカルで作業してテストする場合) コマンドラインでの git サポートがある Node.js 開発環境

アプリを実行するコードを入手する

あらかじめビルドされたコンポーネントを組み合わせて実用的な Web アプリケーションやモバイル・アプリケーションを作成するという発想は、もはや夢物語ではありません。

ステップ 1: アプリケーションとのインタラクションを試す

このサンプル・アプリケーションは起動時に、Bluemix にホストされている REST API エンドポイントから Ajax によって店舗の場所と売上のデータを取得し、取得したデータに応じて臨機応変に初期 UI を作成します。

デスクトップ・ブラウザーに表示された売上アプリケーションの初期 UI のスクリーンショット
デスクトップ・ブラウザーに表示された売上アプリケーションの初期 UI のスクリーンショット
  1. このチュートリアルの「アプリを実行する」ボタンをクリックします。
  2. ブラウザーの幅を狭くして (600px 未満)、端末の画面幅に応じてアプリケーションのレイアウトがどのように変化するのかを確認します。幅を狭くしたら、左上のハンバーガーの形をしたメニュー・ボタンをクリックして、ドロワー・パネルの動作を確認してください。
  3. 別の店舗の場所を選択して、インタラクティブ・マップが更新される様子を観察します。
  4. ツールバーの右上のボタンをクリックして、「Sales (売上)」を選択します。これにより、選択されている店舗の場所での売上グラフが表示されます。
  5. ハンバーガー型ボタンを使用して別の店舗の場所を選択し、それぞれの店舗の売上を表示します。 San Francisco (サンフランシスコ) の店舗の売上グラフのスクリーンショット
    San Francisco (サンフランシスコ) の店舗の売上グラフのスクリーンショット

ステップ 2: コードをフォークするか、独自の Mobile Cloud スターターを作成する

私が作成したコードをフォークすることも、Bluemix Mobile Cloud ボイラープレートを使用して独自のアプリケーションを作成することもできます (その後、変更します)。

  • コードをフォークする場合:
    1. このチュートリアルの「コードを入手する」ボタンをクリックします。続いて DevOps Services で、私のプロジェクトの「EDIT CODE (コードの編集)」ボタンをクリックし (まだログインしていない場合は、ご自身の DevOps Services 資格情報を入力してください)、メニューに表示される「FORK (フォーク)」ボタンをクリックして、自分の DevOps Services ID で新規プロジェクトを作成します。
    2. manifest.yml ファイルを編集して、すべての dwpolymer のインスタンスを、新規に作成したプロジェクトに固有の名前に変更します。
    3. app.js を編集して独自の Bluemix applicationRoute および applicationId を指定します (ライン 6 からライン 10)。
  • ゼロから新しいアプリケーションを追加して変更する場合:
    1. Bluemix カタログで、「Mobile Cloud (モバイル・クラウド)」ボイラープレートを選択します。 BlueMix カタログに表示される「Mobile Cloud (モバイル・クラウド)」ボイラープレート・エントリーのスクリーンショット
    2. 一意に決まる名前を指定してアプリケーションを作成します。 Bluemix で Mobile Cloud アプリケーションを作成するためのダイアログ・ボックスのスクリーンショット
      Bluemix で Mobile Cloud アプリケーションを作成するためのダイアログ・ボックスのスクリーンショット
    3. プロンプトが出されたら、DevOps Services の git リポジトリーを新規アプリケーションに追加します。git コマンドライン・ツールを使用して、git リポジトリーをローカル PC に複製します。その後、以下の変更を行います。
      1. app.js ファイルを、私のリポジトリーから入手した app.js ファイルに置き換えます。
      2. 私のプロジェクトの data ディレクトリーとその中身をコピーして、皆さんのリポジトリーに追加します。
      3. public ディレクトリーを、私のリポジトリーから入手した public ディレクトリーに置き換えます。
      4. app.js を編集して皆さんの Bluemix applicationRoute および applicationId を指定します (ライン 6 からライン 10)。

ステップ 3: ソース・ディレクトリーとその中身を調べる

このステップでは、プロジェクトのディレクトリー構造と以下の重要なファイルを確認します。

  • data/waypoints.json: 以下に示す店舗の位置情報および売上情報を格納する JSON 文書です。
    shortname (短縮名)longitude (緯度)latitude (経度)fullname (フルネーム)hardware (ハードウェア)software (ソフトウェア)services (サービス)
    rh-78.64792935.7866509Raleigh300180800
    sd-117.207097832.8746129San Diego12008902200
    sf-122.3983437.791296San Francisco20003180200
  • public/dwsalescomp/index.html: メインのアプリケーションの HTML。このファイルには、<national-sales-explorer> Web コンポーネントの重要なカスタム HTML タグが 1 つだけ含まれています。
  • public/dwsalescomp/national-sales-explorer.html: Polymer カスタム Web コンポーネントの実装。カスタム Web コンポーネントのコードはすべてここにあります。
  • public/dwsalescomp/sales-datasource/sales-datasource.html: 非ビジュアル Polymer Web コンポーネント。このコンポーネントは、Ajax を使用してバックエンドの REST API エンドポイントにアクセスし、JSON フォーマットにされた売上データおよび位置情報データを取得します。
  • app.js: Bluemix Node.js Mobile Cloud ボイラープレートの一部。REST API エンドポイントに対応するとともに、アプリケーション・コンポーネントおよびカスタム Web コンポーネントを含む静的 HTML ページに対応するように変更されています。

    ボイラープレートの app.js ファイルは、Express Web サーバーのインスタンスを構成して実行します。REST API エンドポイント (データ・ソース) に対応するために、app.js には以下のコードが追加されています。

    app.get(ibmconfig.getContextRoot()+'/getsalesdata', function(req,res) {
         res.sendfile('data/waypoints.json');
    });

    ルート URL へのアクセスを public/dwsalescomp ディレクトリーにリダイレクトするには、app.js に以下のコードを追加します。

    app.get('/', function(req, res){
       res.redirect(ibmconfig.getContextRoot() + '/public/dwsalescomp/index.html');
    });
  • public/bower_components/*: Polymer ライブラリー、Polymer のコア・コンポーネント、Polymer の paper メニュー・ボタン・コンポーネント、売上グラフおよびマップ Web コンポーネント。
  • public/images/dwlogo.svg: ドロワー・パネル UI を作成する際に使用される画像。
  • manifest.yml: アプリケーションを Bluemix にデプロイするために使用されるマニフェスト (DevOps Services プロジェクトをフォークした場合、ステップ 2 でこのファイルをカスタマイズしました)。

データが提供される仕組み

<national-sales-explorer> コンポーネントは、<sales-datasource> という名前の非ビジュアル・カスタム Polymer 要素を使用して、Bluemix 上にホストされている REST API エンドポイントからデータを取得します。

ステップ 4: コードを順に見ていく

コードを順に見ていくこのステップでは、Polymer を使用してカスタム要素を作成するための重要な手法に焦点を当てます。

カスタム Polymer Web コンポーネントのコード構造

以下に記載する national-sales-explorer.html ファイルの構造を見てください。これが、カスタム Polymer コンポーネントの一般的なコード構造です。

<link rel='import' href=../...>

... HTML import of components that are used to compose this component ...

<polymer-element name=national-sales-explorer>
<template>
<style>
... CSS styles used encapsulated within the component ...
</style>

... actual component composition, HTML elements and other web components ...

</template>
<script>

.. JavaScript web component registration, Polymer component prototype ...
</script>
</polymer-element>

CSS スタイル設定のカプセル化

カスタム要素に定義された CSS スタイルの適用範囲は、その要素の shadow DOM 内部に制限され、外部には適用されません。このサンプル・アプリケーションでは、<national-sales-explorer> 要素インスタンスを選択するために、特殊な :host セレクターを使用しています。これにより、google-map<national-sales-explorer> 内の <google-map> Web コンポーネント・インスタンスを選択します。

<style>
    :host {
      display:block;
    font-family: 'RobotoDraft', sans-serif;
    }
    google-map {
      display: block;
      height: 600px;
    }
    ...
</style>

テンプレート・バインディング

左側のスライド式ドロワー・パネルには、waypoints データから店舗の場所のリストが生成されます。そのために使用するのは、Polymer のテンプレート・バインディング拡張です。repeat 属性を設定した <template> 要素を使用することで、waypoints 配列をループ処理することができます。

<template repeat="{{waypoint in waypoints}}">
<core-item icon="explore" label="{{waypoint.fullname}}">
</core-item>
</template>

イベント・バインディング

ユーザーが場所を選択すると、core-menu コンポーネントの core-select イベントが起動されます。この場合のイベント・ハンドラーは、この要素の itemSelected 関数です。ハンドラーを指定するには、Polymer の宣言型イベント・バインディングを使用します。

<core-menu id='menu' selected="0" 
on-core-select="{{itemSelected}}">
...
</core-menu>

双方向のデータ・バインディング

ツールバーのドロップダウン・メニューから「Sales (売上)」を選択するか「Location (場所)」を選択するかによって、表示されるコンテンツが変わります。この場合には、Polymer の宣言型イベント・バインディングは使用されません。コードで代わりに利用しているのは、Polymer の双方向宣言型データ・バインディングです。

ユーザーが選択操作を行うと、<my-menu-button>selected 属性の値が変更されます (「Location (場所)」を選択した場合は 0 に、「Sales (売上)」を選択した場合は 1 に変更されます)。このバインドされた modeSelected オブジェクトは、<core-animated-pages> 要素の selected 属性の値にも使用されています。<my-menu-button>selected 属性が変更されるたびに、<core-animated-pages>selected 属性も同じく変更されて、コンテンツが変更されることになります。以下に <my-menu-button> 要素を示します。

<my-menu-button id='mode' tool icon="more-vert" selected="{{modeSelected}}" 
valign="bottom" halign="right">
</my-menu-button>

これに対応する <core-animated-pages> 要素は以下のとおりです。

<core-animated-pages id=cont selected={{modeSelected}} transition=slide-from-right>
...
</core-animated-pages>

公開プロパティー

双方向データ・バインディングは、非表示コンポーネント <sales-datasource> の waypoints 公開プロパティーでも使用されています。waypoints は、<sales-datasource> コンポーネントの属性として宣言される場合、公開プロパティーになります。

<polymer-element name="sales-datasource" attributes="waypoints">
...
</polymer>

この公開プロパティーは、<national-sales-explorer> 内の waypoints オブジェクトにバインドされたデータです。<sales-datasource> 要素が Ajax によって正常にデータを取得すると、この公開プロパティーが更新され、それによって、バインドされたオブジェクトの値が更新されます。これが、waypoints にデータが設定される仕組みです。

<sales-datasource id="datasource" waypoints="{{waypoints}}">
...
</sales-datasource>

関数とプロパティーの定義

<national-sales-explorer> および <sales-datasource> の両カスタム要素に含まれる <script> には、コンポーネントを登録するための Polymer() 呼び出しがあります。この呼び出しの 2 番目の引数は、カスタム要素の JavaScript プロトタイプです。この引数に、関数 (メソッド) とプロパティーの定義が格納されます。以下に例を示します。

Polymer('global-sales-explorer', 
  {
   created: function() {
               .. initialize properties 
              }, 
   itemSelected: function(event, detail, sender) {
               .. event handler ..
              }
 
  });

Shadow DOM に穴を開けてのアクセス

通常、Web ページに設定された CSS スタイルは、カスタム要素の Shadow DOM に影響を及ぼすことができません。ただし、Polymer には、Shadow DOM に穴を開けて選択的なアクセスをできるようにする特殊な ::shadow セレクターが用意されています。例えば、<global-sales-explorer><core-toolbar> は、index.html の中で以下のようにスタイル設定されます。

global-sales-explorer::shadow  core-toolbar {
      color: white;
      background: red;
      background-color: darkgray;
    }

ノードの自動検出

document.getElementById() を使用して Polymer コンポーネントの DOM 内にあるノードを見つけるのではなく、組み込みの this.$ ハッシュを使用して、同じ Shadow DOM 内のすべての要素を ID によって効率的に見つけることができます。例えば、<national-sales-explorer> 内の itemSelected イベント・ハンドラーを見てください。

var map = this.$.map;
var scaffold = this.$.scaffold;
var location = this.$.location;
var menu = this.$.menu;

既存の Web コンポーネントのサブクラス化 (継承)

「Location (場所)」/「Sales (売上)」選択メニューを実装するために使用されているのは、<my-menu-button> という名前のカスタム要素です。このカスタム要素は、Polymer の <paper-menu-button> コンポーネントをサブクラス化 (継承) することによって実装されています。既存のコンポーネントを継承すると、そのコンポーネントの属性、メソッド、プロパティーがすべて継承されます。

サンプル・アプリケーションの前のバージョンでは、このメニューに Polymer の <core-menu-button> を使用していましたが、このコンポーネントには更新のバグが含まれていました。このバグを回避するために、今回は Polymer の <paper-menu-button> を代わりに使用しています。

<core-menu-button> とは異なり、<paper-menu-button>selected プロパティーを公開しないため、<paper-menu-button> を継承して selected プロパティーを公開する必要があります。

<polymer-element name="my-menu-button" extends="paper-menu-button" attributes="selected">
<template>
  <shadow></shadow>
</template>
<script>
Polymer('my-menu-button', {
 selected: 0,
 observe: {
  '$.menu.selected' : 'menuSelectedChanged'
 },
 menuSelectedChanged: function (oldValue, newValue) {
  this.selected = newValue;
 }
});
</script>
</polymer-element>

ステップ 5: アプリケーションを BlueMix にデプロイする

私のリポジトリーをフォークした場合は、DevOps Services IDE で、自分のプロジェクトの「DEPLOY (デプロイ)」ボタンをクリックしてください。

Mobile Cloud ボイラープレートを使用してゼロからリポジトリーを作成し、ローカルでコードを扱っている場合は、変更したコードを git push によって DevOps Services の git リポジトリーにプッシュすることができます。これによって、Bluemix への自動再デプロイがトリガーされます。

まとめ

Polymer を使用して再利用可能なカスタム要素を作成するのは、単純明快なプロセスです。(Polymer ライブラリーやコミュニティー・リポジトリーにある) 既存のコンポーネントを組み合わせて、何らかの HTML、CSS、および JavaScript によるグルー・コードを適用します。そうして作成されたカスタム要素は、UI、データ・アクセス、ビジネス・ロジックを自己管理する、完全に自己完結型のミニ・アプリケーションになります。

あらかじめビルドされたコンポーネントを組み合わせて実用的な Web アプリケーションやモバイル・アプリケーションを作成するという発想は、もはや夢物語ではありません。最近のすべてのブラウザー・ベンダーが採用して実装している W3C Web Components 標準は、(相当な数の構成済みオープンソース Web コンポーネントを作成することを目的とした世界的なコミュニティーの取り組みもあって)、すでにこの夢を実現し始めています。そして、この夢の実現に拍車をかけているのが、Polymer の JavaScript API とコンポーネント・ライブラリーなのです。


ダウンロード可能なリソース


関連トピック


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Web development, Cloud computing
ArticleID=990389
ArticleTitle=Polymer を使用して再利用可能なカスタム Web コンポーネントを作成する
publish-date=11272014