Pjax を使ってフォームの submit で非同期にページを更新してみた

前回、非常に苦労して Pjax を試しました。

ページ移動を非同期で行えるようになったので、次はフォームの submit 後も同じようにページを移動したい、と考えてしまうのは当然ですよね。これも Pjax でやりたい。


jquery.pjax のソースコードを見たところ、a タグなどの click イベントを捕まえて、非同期でページ更新を行っていました。フォームの submit イベントには対応していません。さて、どうしよう。


Pjax の $.pjax メソッドを使えば、$.ajax みたいに POST リクエストを送信できるので、これを使って自前でフォームデータを送信すれば上手くいきそうです。

<!DOCTYPE html>
<html>
    <head>
        <title>PjaxSample</title>
    </head>
    <body>
        <div id="header">
            <h1>PjaxSample</h1>
        </div>

        <!--PJAX で #main の中が書き変わる-->
        <div id="main">
            <form id="sample-form" method="POST" action="{{ url_for('greet') }}">
                <label>名前</label>
                <input type="text" name="name"/>
                <input type="submit" value="Greet"/>
            </form>
        </div>

        <script type="text/javascript" src="{{ url_for('static', filename='jquery-1.6.2.js') }}"></script>
        <script type="text/javascript" src="{{ url_for('static', filename='jquery.pjax.js') }}"></script>
        <script type="text/javascript">
            $("#sample-form").submit(function(e) {
                if ($.support.pjax) {
                    // PJAX が使えるブラウザのとき
                    var url = $(this).attr("action");
                    var name = $(this).find("input[name='name']").first().val();
                    $.pjax({
                        timeout: 3600,
                        url: url,
                        container: "#main",
                        type: "POST",
                        data: {
                            _pjax: true,
                            name: name
                        }
                    });
                    return false;
                } else {
                    return true;
                }
            });
        </script>
    </body>
</html>


サーバーサイドは Python + Flask でさくっと実装。こんな感じ。

#!/usr/bin/env python
from google.appengine.ext.webapp import util
from flask import (
    Flask, render_template, request,
)

app = Flask(__name__)

@app.route("/")
def index():
    return render_template("index.html")

@app.route("/greet", methods=["POST"])
def greet():
    name = request.form["name"]
    if "X-PJAX" in request.headers:
        return "Hello, %s! (Pjax)" % name
    else:
        return "Hello, %s!" % name

if __name__ == '__main__':
    util.run_wsgi_app(app)

これで一応、フォームの submit 後に Pjax を使って非同期にページを更新できました。しかし、フォームデータを自力で送信してるので、項目が多くなったら地獄になるのは目に見えています。工夫が必要。


そういえば、jQuery Mobile もフォームを submit するとページを非同期で更新していた気がします。参考にしてみるといいかもしれませんね。