Doge log

Abby CTO 雑賀 力王のオフィシャルサイトです

JSFとAjaxは共存しにくい!?

S2JSF meets Dojo
S2JSFDojoで非同期通信をやってみる。
まーふつーのひとはDWRあるいはAjaxFaccesを使うんでしょうが。
無謀にもDojoで非同期通信をやってみよう。
っていうかjavadojoを組み合わせてる人みたことないね。

手っ取り早くS2JSFのサンプルを改造して実験。
えーっと親のhtmlにjavascriptを追加

layout.html
<script type="text/javascript" src="../js/dojo.js"></script>
<script type="text/javascript" src="../js/ajax.js"></script>

ajax.jsは自作のthinラッパーです。

ajax_test.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">
<form id="form1">
	<a id="dummy1" m:action="#{addAction.ajax}"/>
	<a href="javascript:ajax_link('form1' ,'form1:dummy1', 'blk');">ajax.link</a>
</form>
<div id="blk"></div>
</span>
</body>
</html>

ActionはAddActionを流用させてもらうことにする。
上にもあるように呼ぶのはAddAction.ajaxメソッドです。

でAddActionにメソッド追加

AddAction.java
    public String ajax();

実装は適当です。

AddActionImpl.java
    public String ajax() {
        addDto.setAjax("Test");
        return "ajax";
    }

返すのは"ajax"ですがそれは"/ajax/test.html"を呼ぶように設定してます。
(この辺割愛)

/ajax/test.html
<html xmlns:m="http://www.seasar.org/maya">
<span m:inject="s:insert">
<table border="1">
<tr>
<td>
<span m:value="#{addDto.ajax}"/>
</td>
</tr>
</table>
</span>
</html>

で肝心のjavascript

ajax.js
dojo.require("dojo.io.*");

function ajax_link(form_id, link_id, target_id){
  var f = document.forms[form_id];
  f.target='';
  f.elements[form_id+':_link_hidden_'].value=link_id;
  var node = document.getElementById(target_id);
  var bindArgs = {
      load: function(type, data, evt){
        node.innerHTML = data;
      },
      formNode:document.getElementById(form_id),
      method:'POST',
    };  
    var canBind = dojo.io.bind(bindArgs);
}

対象formとdummyのlinkのid、結果の出力先を設定。
準備はここまで。割とすんなり書ける。

リンクをクリックすると

DEBUG 2006-04-06 19:19:42,078 [http-8080-Processor25] BEGIN examples.jsf.action.impl.AddActionImpl#ajax()
DEBUG 2006-04-06 19:19:42,078 [http-8080-Processor25] END examples.jsf.action.impl.AddActionImpl#ajax() : ajax
2006-04-06 19:19:42,078 [http-8080-Processor25] DEBUG org.apache.myfaces.renderkit.html.HtmlRenderKitImpl - No content type list given, creating HtmlResponseWriterImpl with default content type.

む。AddActionImpl#ajax()は呼ばれてる。
画面にも文字が出たなあ。
でも実際帰ってくるデータは

<html>
<BODY>
Test
</BODY>
</html>

ふーむ・・・。まあaddDto.ajaxは正しく取れてるな。
ホントは平文返してみたいんだけど。
でやってみようかなと。

/ajax/test.html
<span m:inject="s:insert" >
<span m:value="#{addDto.ajax}"/>
</span>

どうもこんなんとかかけないみたい。
でさらに固定でやってみた。

/ajax/test.html
TestAjax!

の結果は

<html>
<BODY>
TestAjax!
</BODY>
</html>

ふーむ。基本的にタグは絶対ついてきてしまうようだ。
ぬー。タグはいらなかったりするけど。
やっぱ動的に平文を返せないといった感じか。
javascriptでevalできないなあ。
やるんであれば

  1. XMLを返す
  2. javascriptXMLをばらす
  3. eval実行

って事になりそうだがめんどくさい。
うーん。うまい方法があるのかないのか。
そもそもやろうというのが無謀なのか。
Teedaはどうなんだろ?
そもそもFacesっていってるくらいなのでやっぱりタグの呪縛から逃れられないのか。
HttpResponseをぐりんといじれないとAjaxは辛いものがあるなあ。
ぬー。もうわからん。

追記

私嘘をついておりました。
できます。できないことはないのです。

AddActionImpl.java
   public String ajax() throws Exception {
        FacesContext facescontext = FacesContext.getCurrentInstance();
        ExternalContext externalcontext = facescontext.getExternalContext();
        HttpServletResponse response = (HttpServletResponse) externalcontext.getResponse();
        response.setContentType("text/javascript/");
        BufferedWriter o = null;
        try {
            o = new BufferedWriter(new OutputStreamWriter(response.getOutputStream()));
            o.write("alert('AJAX');");
            facescontext.responseComplete();
        } finally {
            if (o != null) {
                o.close();
            }
        }
        return "";
    }

FacesContext使えばよいのですな。

ajax.js
dojo.require("dojo.io.*");

function ajax_link(form_id, link_id, target_id){
  var f = document.forms[form_id];
  f.target='';
  f.elements[form_id+':_link_hidden_'].value=link_id;
  var node = document.getElementById(target_id);
  var bindArgs = {
      load: function(type, data, evt){
      		
//       alert(data);
//        node.innerHTML = data;
      },
      formNode:document.getElementById(form_id),
      method:'POST',
      mimetype:'text/javascript',
    };  
    var canBind = dojo.io.bind(bindArgs);
}

実行するとダイアログが出るはずです。
ぬふふ。
後はjavascriptBuilderをjavaで書いて結果を返せばいいだけだー!
javascript隠蔽したろ。
これでRailsのRJSチックにエフェクトその他もろもろかなり動的に実行できますなあ。
データが○○の時は色変えたり、エフェクト変えたりとかね。
javascriptBuilderさえ作れればDWRより手順は少なそうだね。
うくく。