2010年7月9日金曜日

zend + dojo : 画像のsubmitの挙動が変だったハナシ

Zend + Dojoで画像ボタンでsubmitしようとしたんですが、サーバからの返却が何やらおかしかった。
<input type="submit">を<input type="image" src="">にしたい場面はたくさんありますが、ajaxでの接続で挙動がおかしい場面があったのでメモ。

通常のボタンでsubmitする場合

※HTML

<form action="#" id="hoge">
    <button name="btn_submit" id="btn_hoge" type="button" value="hoge">hoge</button>
</form>

// dojo.connect
<script type="text/javascript">
    // イベントハンドラの登録
    dojo.addOnLoad(function() {
        // btn_hoge要素にイベントハンドラを設定する。
        // onclickイベントを引っ掛けて、hogeフォームの内容をsubmit
        // /fuga/piyoアクションをコールして、json形式でレスポンスを受け取る。
        dojo.connect(dojo.byId("btn_hoge"), "onclick", function() {
            dojo.xhrPost({
                url: "/fuga/piyo/format/json",
                content:{"a":"b"},
                form: "hoge",
                handleAs: "json",
                load: function(data){
                    alert('OK');
                },
                error: function(error, args) {
                    alert('NG');
                }
            });
        });
    });
</script>
※Zend

/**
 * Fugaコントローラ
 */
class FugaController extends Zend_Controller_Action
{
    /**
     * piyoアクションのコンテキストとしてjsonを登録
     */
    public function init()
    {
        parent::init();
        $contextSwitch = $this->_helper->getHelper('contextSwitch');
        $contextSwitch->addActionContext('piyo', 'json')
                      ->initContext();
    }

   /**
     * Piyoアクション
     */
    public function PiyoAction()
    {
        // View変数をシリアライズしてjsonとして返却
        // {"viewMessages":"abc"}
        $this->view->message = 'abc';
    }
}

上記は、普通にajax通信できますが、以下のようにボタンを画像にすると、dojoのイベントハンドラでerror関数がコールされ、error変数として「Error: Unable to load /fuga/piyo/format/json status:0」という良く分からないエラーが返却されます。

※HTML

<form action="#" id="hoge">
    <input type="image" src="" name="btn_submit" id="btn_hoge" value="btn_submit" />
</form>

サーバでログ取ってみても、postされてたりされてなかったり、規則性なくランダムにサーバにリクエストが到達しているようでした。
error関数も複数回コールされることがあり、1回のボタン押下で何回か/puga/piyoアクションがコールされることもありました。

何でそんなことになるのか分かりませんでしたが、dojo.connectでinput属性のエレメントにハンドラを設定しているのが問題っぽい。

<form action="#" id="hoge">
</form>
<input type="image" src="" name="btn_submit" id="btn_hoge" value="btn_submit" />

こんな感じでformの外にimage要素を配置すると、サーバには1回だけ行儀よくPOSTし、返却値も期待するJSON形式で受け取れるようになります。

formの中にいる<input type="image">な要素にdojo.connectすると、dojoで接続されたイベントハンドラと、form自体のactionとの両方が実行されてしまうようです。

0 件のコメント:

コメントを投稿