55
55

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

AngularとPolymerが共存する世界への第一歩

Last updated at Posted at 2015-06-09

はじめに

Polymer 1.0がリリースされました。WebComponentsの普及のためにPolymerには頑張ってもらわないといけませんが、そのためには現在Webで大きなシェアを占めるフレームワーク、AngularJSとの共存が不可欠です。その共存の理想と現実、未来について個人的な考えをまとめます。

そもそも対立構造ではない

何故か一部のプログラマの中では「AngularJS vs Polymer」になっているような空気を時々感じますが、本来PolymerはAngularJSと競合する技術スタックではありません。
Polymer、というよりWebComponents(特にCustom Element)はAngularJSやその他のMVCフレームワークよりも低いレイヤーのWeb技術で、むしろ共存できなければならないものです。

Polymer+Angularのあるべき姿

Polymerが提供するのはCustom Elements(独自タグ)の定義を簡単にするAPIです。PolymerのAPIを利用して定義された独自タグはWebComponents仕様に準拠しているがゆえに、同じWebComponents技術を利用するレイヤー上では再利用可能です。この再利用性を高めるのにWebComponentsのHTML Imports技術が大きく寄与しています。

<!DOCTYPE html>
<html>
  <head>
    <script src="bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
    <link rel="import" href="dom-element.html">
  </head>
  <body>
    <dom-element></dom-element>
  </body>
</html>

WebComponentsのAPIにより新たに定義されたタグは、アプリケーション側から見た時にHTML5標準のタグと何か差があるかというと、無い、あってはならないというのが理想です。
ここでAngularが<dom-element>にバインディングを行うのと、<div>にバインディングを行うのに、なにか違いがあってはならないのです。

Polymer+Angularの現在

とはいえ、未だPolymerとAngularの世界は重なっておらず、ng-modelはPolymerの世界には通用しません。

次のPolymerElement(Polymerにより定義されたCustom Element)<input-binding>はinput要素のvalueをバインドして表示するだけの要素です

<link rel="import" href="../bower_components/polymer/polymer.html"/>
<link rel="import" href="../bower_components/paper-input/paper-input.html"/>
<link rel="import" href="../bower_components/iron-input/iron-input.html"/>

<dom-module id="input-binding">
  <template>
    <paper-input-container>
      <input is="iron-input" bind-value="{{text}}"
             placeholder="text">
    </paper-input-container>
    <strong>{{text}}</strong>
  </template>
</dom-module>

<script>
  Polymer({
    is: "input-binding",
    properties: {
      text: {
        type: String,
        notify: true
      }
    }
  });
</script>

PolymerElementのテンプレート内部でinput要素のvalueにバインドするにはbind-value要素にプロパティをセットします。PolymerElementが持つプロパティはpropertiesで定義され、textプロパティはString型で、外部に変更通知をnotifyすることが記述されています。

一方、AngularJSでinputの値をバインドするにはng-modelを使うのが一般的です。

  <input style="width: 100%" type="text" ng-model="text"/>

  <p>{{ text }}</p>

ここで、<input-binding>textをAngularでバインドし、<p>に表示したいときどうしたらいいでしょうか?

  <input-binding text="{{ text }}"></input-binding>

  <p>{{ text }}</p>

一見双方向バインディングされているように見えますが、PolymerElementに対するフックがAngularJSには(当然ながら)定義されていないので、text属性が<input-binding>の内部から書き換えられたとしてもそのイベントは{{text}}に伝播することはありません。
ですが、PolymerElementが何も情報を発していないわけではなく、PolymerはPolymer語で、
textプロパティが変更されたらtext-changedイベントを発火する」という仕事をしています。

必要なのはPolymer語のイベントを聞き取り、Angular語に翻訳する「通訳」です。

Directiveを使って通訳する

一つの解決策として、Polymer語を翻訳するDirectiveを定義してみました。polymer-attr属性をPolymerElementに付与することで、内部の変更をAngularのScopeに反映します。

app.directive("polymerAttr", function () {
  return {
    restrict: 'A',
    link: function (scope, element, attr) {
      var eventName = attr.polymerAttr + '-changed';
      element.on(eventName, function (event) {
        scope[attr.polymerAttr] = event.detail.value;
        scope.$apply();
      });
    }
  };
});

これは<property>-changedに関してはすべてのPolymerElementに適用できる汎用のDirectiveです。

これを付与し、textプロパティの変更をAngular側で受け取ります。

  <input-binding text="{{ text }}" polymer-attr="text"></input-binding>
  <p>{{ text }}</p>

これによってアプリケーション開発者はpolymer-attrを使うだけで、PolymerとAngularの垣根なく双方向バインディングを行うことが可能になりました。

Polymer+Angularの今後

今回挙げた「通訳」の例はたったひとつのイベントに対する解決策であり、他にもいろいろなDSLに対する通訳が必要ですが、それでもこれだけの記述でPolymerとAngularの世界をつなぐことができることがわかりました。

Polymerは本質的にはWebComponentsのpolyfillであり、糖衣構文です。Polymerは1.0になりましたが、そのAPIの使いやすさは正直なところそれほど高くないです。しかし競争相手となるライブラリがMozillaのX-Tagくらいしかなく、X-TagはPolymer以上に使いにくいAPIなので困ったものです。
ですが、この状態は本来WebComponentsと親和性の高いES6のclass記法が使えるようになれば大きく変わることが期待できます。

WebComponentsが普及した先では、再利用可能なタグを開発し配布するコンポーネントエンジニアと、それを利用するアプリケーションエンジニアに二分され、後者はそれがHTML5のタグなのか自分でインポートしたタグなのか気にすることなく自由にアプリケーションを開発できるようになります。この構図は自分がインストールしたjQueryプラグインがjQuery標準のAPIと同じように扱えるのと全く同じです。そして、AngularJSが今ではjQueryと共存できているように、WebComponentsもいずれはもっと自然にAngularと共存できるようになるはずです。具体的には、Angular2のコンポーネントシステムがWebComponentsに準拠することでPolymerとAPIを共通化できるのではないかと考えています。

まとめ

WebComponents技術は今後必ずWebアプリケーション開発の中で重要なパーツになります。その取っ掛かりとしてPolymerに今から触れておくのは決して無駄な投資にはならないでしょう。
「Angularを使っているから」と避けていた方は1.0リリースをきっかけに手を出してみてはどうでしょうか?

55
55
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
55
55

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?