AjaxHelper::editorあれこれ
昨日ハマったんで備忘録的に。Ajax.InPlaceEditorについて。
AjaxHelper::editorはほんとに地獄だぜー(AA略
CakePHP: AjaxHelper::editorでonFailureは出来ない?を参照していただくとわかるとおり、$options['onFailure']が投げれない。
正確には
$ajax->editor($id,$url,array('onFailure'=>"alert('hoge');"))
というとき、
new Ajax.InPlaceEditor('id','url',{ajaxOptions:{asynchronous:true, evalScripts:true, onFailure: function(){ alert('hoge'); }}}
のようにajaxOptions内にレンダリングされてしまうのが問題の根幹。
場当たり的な対応だが、これはAjaxHelperのajaxOptionsとeditorOptionsの値をインスタンス生成後に書き換える事で一応回避できる。
つまり、AjaxHelperを使おうとするviewの*.ctp内の最初の行あたりに
$ajax->editorOptions = am($ajax->editorOptions,array('onFailure')); unset($ajax->ajaxOptions['onFailure'])
で、onFailure項がAjaxHelper::__optionsForAjax()から_buildCallbacks()にかけて解釈されないようにしてしまう。
逆に言うとこのプロパティの調整によりajaxOptions側にonFailureが投げれなくなるが、Ajax.Responders.registerで
対応するのが筋って気がしてるので気にしない事にする。
これでめでたくonFailureが投げられるのだが、_buildCallbacks()経由じゃないから、function(){}でラッピングしてくれないので自分でやらないとダメ。
$ajax->editor($id,$url,array('onFailure'=>"function(ipe,transrator){ alert('hoge'); }"))
こんな感じ。
これで動くと思ったら大間違い
ここでさらに問題。今度はAjax.InPlaceEditor側(Javascript側)の問題。
RoR本家でもいくつかチケットが出てたが、InPlaceEditorのonFailureがトリガされないというもの。
このBlogで紹介されているパッチをscript.aculo.usの後に読み込んで置くことでこのバグは解消されます。ただし将来のバージョンでどーなるか不明なので自己責任で!
で、ぶっちゃけCakePHP側でバリデーションどうすんのよ?
上記のコードでいうところの$urlに対してPOSTで値がやってくるのですが、エラーが発生したらどうするか?
$url=array('controller'=>'hoges','action'=>'edit',$id)だとして
class HogesController extend App_Controller{ function edit( $id ){ $field = $this->params['form']から適当にパース; $data = $this->params['form']から適当にパース; $this->Hoge->id = $id; if(!$this->Hoge->saveField($field, $data, true){ $this->redirect(null,500,true); // redirect()でexitしちゃう } } }
status 500を返すのがHTTP的な良し悪しはともかくとして、Ajax.InPlaceEditor側のonFailureは目出度く動作するはず。
Ajax.InPlaceEditor(正確にはAjax.Updater)はonFailureがトリガされたときはevalScripts:trueで投げててもevalしてくれないので
// views/hoge/index.ctp // onFailure的なおまじない $ajax->editorOptions = am($ajax->editorOptions,array('onFailure')); unset($ajax->ajaxOptions['onFailure']) // onFailureでもevalしちゃえ>< $ajax->editor($id,$url,array( 'onFailure'=>"function(ipe,transrator){ transrator.responseText.evalScripts(); }" ));
で、バリデータ側は
class HogesController extend AppController{ function editor( $id ){ $field = $this->params['form']から適当にパース; $data = $this->params['form']から適当にパース; $this->Hoge->id = $id; if(!$this->Hoge->saveField($field, $data, true){ loadHelper('javascript'); $javascript = new JavascriptHelper(); $this->redirect(null,500); //exitしない echo $javascript->codeBlock(sprintf("alert('%s');",$errorMessage)); //Javascirptはいちゃえ exit(); } // views/hoge/editor.ctpに行く } }
と、こんな感じで動きましたとさ。
動作環境 : script.aculo.us-1.8.1 + InPlaceEditorパッチ + CakePHP 1.2RC3
ついでにFormHelper::datetimeの$attirbutes['interval']バグ
https://trac.cakephp.org/changeset/7711 本家リポジトリのChangesetの通りだけど、$timeFormat = '24'の時
intervalが無視されちゃう件。パッチ当てる以外解決方法無し!