JSFとAjaxは共存しにくい!?その2
引き続きS2JSFとDojoでチャレンジ。
昨日は昨日であんな風にできそうだと思ったけどやっぱテンプレート使わないとしんどいかもな。
HTMLとBODYが入ってくるのでそいつを抜いてevalさせる方法。
以下DWR嫌いかつ豪腕な人向け。
S2JSFの計算サンプル(AddAction)をajaxでやるように改造してみよう!
ということでまず土台のjavascriptを作成。
javascript:ajax.js
dojo.require("dojo.io.*"); dojo.require("dojo.html"); dojo.require("dojo.dom"); dojo.require("dojo.fx.*"); function ajax_link(form_id, link_id){ var f = document.forms[form_id]; f.target=''; f.elements[form_id+':_link_hidden_'].value=link_id; var bindArgs = { load: function(type, data, evt){ var xml = dojo.dom.createDocumentFromText(data); var b = dojo.dom.nextElement(xml.firstChild.firstChild); var text = b.childNodes[0].nodeValue; dj_eval(text); }, formNode:document.getElementById(form_id), method:'POST', }; var canBind = dojo.io.bind(bindArgs); } function insert_html(position, id , data){ node = dojo.html.createNodesFromText(data, false); dojo.dom.insertAtPosition(node[0], document.getElementById(id), position); } function replace_html(id, data, raw){ if(raw){ dojo.dom.textContent(document.getElementById(id), data) }else{ node = document.getElementById(id); node.innerHTML = data; } } function fade(id, time, func){ var t = 1; if(time){ t = time; } dojo.fx.html.fadeOut( document.getElementById(id), t, function(n){ if(func){ func(); } dojo.fx.html.fadeIn(n, t); } ); } function wipe(id, time, func){ var t = 1; if(time){ t = time; } dojo.fx.wipeOut( document.getElementById(id), t, function(n) { if(func){ func(); } dojo.fx.wipeIn(n, t); } ); } function colorfadeIn(id, time, color, func){ var t = 1; if(time){ t = time; } dojo.fx.html.colorFadeIn(id, t, color, t, func); } function colorfadeOut(id, time, color, func){ var t = 1; if(time){ t = time; } dojo.fx.html.colorFadeOut(id, t, color, t, func); }
む。DOMのソースはちょーてきとーです。
要はdj_evalが重要なのでそこだけ注意。
でできること
- insert_html : 指定IDの要素の指定位置にデータを入れる
- replace_html : 指定IDの要素にデータを上書き
- fade fadeIn、: fadeOutするEffect
- wipe wipeIn、: wipeOutするEffect
- colorfadeIn : 色をfadeInするEffect
- colorfadeOut : 色をfadeOutするEffect
EffectはEffect実行後にさらに実行するfunctionを指定可能。
(特にfade、wipeはOut、Inをはさんでいる)
で結果を返すテンプレート
html:/ajax/test.html
<html xmlns:m="http://www.seasar.org/maya"> <span m:inject="s:insert" > replace_html('title', '計算しました'); wipe('test', 500, function(){replace_html('test', '結果は<span m:value="#{addDto.result}"/>');}); colorfadeIn('test', 1000, [250,100,0]); </span> </html>
おー豪腕だ。
無理やり埋め込んでるね。
実際結果を返す人は上記で作ったjavascriptさえ知っていればなんとかなります。
このサンプルだと
- idがtitleの要素を”計算しました”と上書き
- idがtestの要素に計算結果をwipeOut、wipeInしながら上書き
- idがtestの要素に計算結果出力先がわかるように色付け
といった感じ。
で呼び出し元は
html:/hello/hello.html
<html xmlns:m="http://www.seasar.org/maya" m:extends="/WEB-INF/layout/layout.html"> <head> <meta http-equiv="Content-Type" content="text/html; charset=Windows-31j" /> <title>Test</title> </head> <body> <span m:inject="f:param" m:name="layoutTitle" m:value="Hello"/> <span m:inject="s:insert" m:name="body"> <h3 id='title'>計算します</h3> <form id="form1"> <input type="text" m:value="#{addDto.arg1}"/> + <input type="text" m:value="#{addDto.arg2}"/> = <span m:value="#{addDto.result}"/> <a id="dummy1" m:action="#{addAction.ajax}"/> <input type="button" value="calculate" onclick="javascript:ajax_link('form1' ,'form1:dummy1');"/> </form> <span id='test'/> </span> </body> </html>
あんまし難しいことしてません。
<a id="dummy1" m:action="#{addAction.ajax}"/> <input type="button" value="calculate" onclick="javascript:ajax_link('form1' ,'form1:dummy1');"/>
これで終わり。
こちらは割とスッキリ。
で呼び出してるmethodはaddActionのajaxメソッドですが、中身はcalculateと同じです。
ajaxメソッド
public String ajax() { int result = addLogic.calculate(addDto); addDto.setResult(result); return "ajax"; }
"ajax"は"/ajax/test.html"が変えるようにfaces-configに設定済み。
/ajax/test.htmlは上記に書いたとおりjavascriptが書いてあります。
これで終わり。
実際動かすとwipeってかっこいいと思えてきます。
(なんかすげーみたいな)
利点って程でもないけどこの方法だと
- 1回の通信で複数のデータを複数の場所に表示できる
ってことができます。
ajaxでvalidatorとかする場合にメッセージをどう運ぼうかとか悩んだときとかにevalできると楽です。
DWRでやりにくい事がある場合はこのような方法もあるよってサンプルでした。
まあハッキリ言ってこの手のやり方はあんまりjavaじゃ受け入れられんだろな。
細かい不備はありまくりですが以上。
うくく。