Play Pjax
Play! framework Advent Calendar 2011 jp #play_ja : ATND の9日目です。
Play framework で、Pjaxを実現する方法について書きます。
Pjax については、pjax こそが pushState + Ajax の本命 - punitan (a.k.a. punytan) のメモが詳しいのでそちらを参照してください。簡単にいうと、Ajaxを使って画面の一部を動的に更新する仕掛けなんだけど、URLもページの中身に合わせてちゃんとしていますよ、というものですね。Pjax を使うととてもスマートな開発しているように感じられて、いい気持ちになれますよ。
サンプルソースは、ironpeace/PlayPJAX · GitHubにアップ済みです。このサンプルを元に説明していきます。
まずは画面実装
#{extends 'main.html' /} #{set title:'Play PJAX' /} #{get 'moreScripts' /} <script src="@{'/public/javascripts/jquery.pjax.js'}" type="text/javascript" charset="${_response_encoding}"></script> <script type="text/javascript"> $(function(){ $("a.js-pjax").pjax("#main"); }); </script> <a href="/?data1=foo" class="js-pjax">/?data1=foo</a> <div id="main"> #{if results} *{ #{result /}とやってしまうと駄目。 }* #{include 'tags/result.html' /} #{/if} </div>
PlayPJAX/app/views/Application/index.html at master · ironpeace/PlayPJAX · GitHub
jquery.pjax.jsを使っています。
defunkt/jquery-pjax · GitHubからダウンロードしたものです。
$("a.js-pjax").pjax("#main");
/?data1=fooのリンクをクリックすると、 < div id="main" > 内にリターンが入ります。
#{include 'tags/result.html' /}
result.htmlがhtml部品として < div id="main" > 内に入ります。result.html の中身は後述します。
#{result /}とやってしまうと駄目。とコメントを入れていますが、実はここが一番ハマったところです。include と書こうが書くまいが効果は一緒のはずなのですが、include で書かないとうまく動いてくれません。
resultタグ
<h3>result</h3> <ul> #{list items:results, as:'result' } <li>${result}</li> #{/list} </ul>
PlayPJAX/app/views/tags/result.html at master · ironpeace/PlayPJAX · GitHub
こいつが index.html の < div id="main" > 内に入るわけですね。
サーバサイド実装
package controllers; import play.*; import play.mvc.*; import play.mvc.Http.Request; import java.util.*; import models.*; public class Application extends Controller { public static void index() { String data1 = params.get("data1"); if(data1 == null){ render(); }else{ List<String> results = new ArrayList<String>(); for(int i=0; i<10; i++){ results.add("data" + i); } if(isPjax()){ render("/tags/result.html", results); }else{ results.add("directCalled"); render(results); } } } private static boolean isPjax(){ if(params._contains("_pjax")){ return true; }else if(request.headers.containsKey("X-PJAX")){ return true; }else{ return false; } } }
PlayPJAX/app/controllers/Application.java at master · ironpeace/PlayPJAX · GitHub
isPjax
このメソッドでPjax通信かどうかを判断しています。GETであればクエリストリング、POSTであればヘッダーを参照して判断します。
メイン実装
if(isPjax()){ render("/tags/result.html", results); }else{ render(results); }
Pjax 通信の時は、result タグだけ応答して、そうでない時は index.html 全体を応答します。これだけです。
まとめ
PlayFramework では HTML の一部を部品かするテンプレート機能があるので、 Pjax の実装もとても簡単に効率的に行うことができます。
以上です。
アドベントカレンダーなかなか楽しいですね(^^
明日は、@somali_cat さんです!