今回はCatalystはあんまり関係なくて、prototype.jsの使い方に関する補足、といった感じです。
前回のエントリの最後で、「xmlHttpRequestで取得したデータを、単純にそのままHTMLにはめ込むだけなので、サーバ側で生成したデータを、Javascript側で何らかの処理をしてからHTMLにはめ込むという用途には使えませんが、単純なajaxアプリであれば十分使えるかと。」ということを書いたのですが、これはHTML::Prototypeが吐き出すJavascriptが、基本的にAjax.Updaterという関数を使っているからですね。なので、prototype.js自体が、「Javascript側で何らかの処理をしてからHTMLにはめ込む」という処理ができない、というわけではないです。
この様な処理をするには、具体的には以下の様なコードになります。ただしこの方法では、HTML::PrototypeやCatalyst::Plugin::Prototypeが使えないので、若干手間が増えます。
<script type="text/javascript" src="prototype.js"></script> <script type="text/javascript"> function completed(request){ var data = request.responseText; // 何か処理をする... } </script> <form onsubmit="new Ajax.Request( '/url', { parameters: Form.serialize(this),onComplete: function(request){ completed(request) } } ) ; return false;"> <input type="text" name="text" /> <input type="submit" /> </form>
肝になるのはAjax.Requestという関数を使っていることと、「onComplete」の部分ですね。この部分で、xmlHttpRequestでサーバからデータを取得完了した時点で実行する関数を指定できます。requestはxmlHttpRequestオブジェクトなので、呼び出した関数内で、request.responseTextでサーバからのデータを取り出すことができます。その上で取得したデータに対して何か処理してやれば良い、ってわけですね。
HTML::PrototypeやCatalyst::Plugin::Prototypeが使えないのはちょっと痛いですが、Ajax.Request関数の書式に慣れてしまえば、自分でxmlHttpRequest周りのコードを書かなくて良いのですから、メリットの方が大きいと思います。
で、実際に上の方法を用いて、ajaxでdel.icio.usを使いやすく #0のdel.icio.usサイドバーのJavascript部分を書き直してみると、どんな感じになるのか見てみることにします。
まず、prototype.jsを使わずに何も考えずに書いたもの。(xmlHttpRequestを使っているfunctionのみ抜き出しています。)JSON形式のデータを受け取って、evalでオブジェクトに変換する、という処理です。
function init() { tagsArea.innerHTML = '<p class="loading">loading tags ...</p>'; var req1 = new XMLHttpRequest(); if(req1){ req1.onreadystatechange = function() { if (req1.readyState == 4 && req1.status == 200) { eval('tagsListObj = ' + req1.responseText); displayTags(); } }; req1.open('GET', '/delside/index.cgi'); req1.send(null); } var req2 = new XMLHttpRequest(); if(req2){ req2.onreadystatechange = function() { if (req2.readyState == 4 && req2.status == 200) { eval('tagToLinkObj = ' + req2.responseText); } }; req2.open('GET', '/delside/index.cgi?rm=tagToLink'); req2.send(null); } }
次にprototype.jsのAjax.Request関数を使って書き直したもの。
function init() { tagsArea.innerHTML = '<p class="loading">loading tags ...</p>'; new Ajax.Request( '/deislde/index.cgi', { method: 'GET', onComplete: function(request){ eval('tagsListObj = ' + request.responseText); displayTags(); } }); new Ajax.Request( '/delside/index.cgi?rm=tagToLink', { method: 'GET', onComplete: function(request){ eval('tagToLinkObj = ' + request.responseText); } }); }
太字部分が変更された箇所です。若干ですが、コードがすっきりしましたよね?
以上、prototype.jsがこんな風にも使える、という例でした。おしまい。