自由課題

学んだり、考えたり、試したりしたこと。

Polymerでscriptタグを使わずにAJAXする方法

はじめに

ぼちぼち勉強していたら、Google I/Oでブチあげられて俄然注目度が上がってきた(?)Polymerに関してです。 (関連記事は Polymer - 自由課題 を参照)

リファレンスを見ていたら、<core-ajax>というエレメントが用意されているのを見つけました。確か公式チュートリアルの中でも出てきていたように思います。

このcore-ajaxと、以前訳したこともあるPolymerのデータバインディング機能を合わせて使えば、JavaScriptのコードを書かなくてもAJAXができるのではないかと思って試してみました。

今回はYoutubeJSON feedを取得・解析してHTMLとして表示するエレメントを作ってみることにします。使う側のコードとしてはこんな感じです。

<!DOCTYPE html>
<html>
  <head>
    <!-- 1. Load platform.js for polyfill support. -->
    <script src="bower_components/platform/platform.js"></script>

    <!-- 2. Use an HTML Import to bring in the element. -->
    <link rel="import" href="youtube-entries/youtube-entries.html">

  </head>
  <body>
    <!-- 3. Declare the element. Configure using its attributes. -->
    <youtube-entries url="http://gdata.youtube.com/feeds/api/standardfeeds/most_popular?alt=json"></youtube-entries>

  </body>
</html>

<youtube-entries>というエレメントが今回作るものになります。表示するyoutubeの動画の情報を取得するURLをurl属性で指定します。

とりあえず今回作ってみた<youtube-entries>のコード(というかHTML)です。

<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../bower_components/core-ajax/core-ajax.html">


<polymer-element name="youtube-entries" attributes="url" noscript>
  <template>
    <style>
      .entry {
        width:300px;
        height:300px;
        margin:10px;
        float:left;
        background-color:#EEEEEE;
        overflow:hidden;
      }
      .title_back {
        height:75px;
        background-color:#111111;
      }
      .title {
        color:#EEEEEE;
        margin:0px;
        padding:5px;
      }
    </style>

    <core-ajax url="{{url}}" handleAs="json" auto response="{{resp}}"></core-ajax>
    <template repeat="{{ent in resp.feed.entry}}">
      <div class="entry">
        <div class="title_back">
          <p class="title">{{ent.title.$t}}</p>
        </div>
        <a href="{{ent.link[0].href}}">
          <img src="{{ent.media$group.media$thumbnail[0].url}}">
        </a>
      </div>
    </template>
  </template>
</polymer-element>

<template>タグの中に<style>タグを記載することで、エレメントの中でCSSの設定ができます。今回は適当に設定しました。

<core-ajax url="{{url}}" handleAs="json" auto response="{{resp}}"></core-ajax>でXHRを行い、取得したレスポンスをrespという変数に詰めています。auto属性を使用することによりurl属性が変更された時に自動でXHRを行ってくれます。また、handleAs属性でJSONを指定することにより、respにデータを詰める際にJSON.parse()を実行してくれます。JSONの他にもXML/blobなどが使用可能です。詳細はリファレンスを参照してください。

<core-ajax>以下の<template>タグの中に、取得したrespを使用してHTMLを生成する処理が入っています。<template>タグにrepeat属性を指定することで、配列オブジェクトの各要素に対して繰り返し処理を行わせることができます。今回は取得したfeedの各エントリ毎(resp.feed.entry)に処理を行っています。repeat属性に{{ent in resp.feed.entry}}と指定することにより、for-in文のようなフィーリングで各要素(ent)を処理できます。

<template>タグの中では、普通にentにアクセスしてHTMLを構築するだけです。今回は動画のタイトル・サムネイル画像・動画へのリンクを使ってみました。本当に簡単。

実際にブラウザで閲覧するとこんな感じになります。Chromeを使うとShadow DOMの中身も見ることができます。

f:id:kimito_k:20140706151841p:plain

今回作ったコードのGitHubリポジトリこちら。サーバサイドのコードは全くないので、clone/ダウンロードしてブラウザからindex.htmlにアクセスするだけで動作します。

まとめ

というわけで、<core-ajax>を使用することにより、<script>タグによりJavaScriptを書かずにAJAXができることがわかりました。実際に使うにはエラーハンドリングなども検討する必要がありますが、こうなるとある種のテンプレートエンジンのような趣もあり面白いと思いました。

余談ですが、実は今回一番苦労した点はCORSでアクセス可能なWebサイトが見つからなかったところでした(探し方が悪いだけ?)。フィードにAccess-Control-Allow-Originヘッダを設定しているサイトは少ないのかもしれません。