そんなことをやってみたので、簡略化して、載せてみる。
で、ファイルは以下のような感じ。面倒なので、全部同じディレクトリにしてみた。
HTMLファイルを見れば、わかるが、prototype.jsを読み込んでから、sample_ajax.jsを読み込む。
おそらく、世間一般に広まっているprototype.js1.3.1では、動かない。まぁ、そんな感じ。
サンプルは「ここ」のページにあります。
- sample_ajax.js(下のソース)
- prototype.js(1.4.0)
- HTMLファイル(sample_ajaxhtml)
- Aの読み込み
- Bの読み込み
sample_ajax.js
var AjaxParent = Class.create();
AjaxParent.prototype = {
initialize: function() {
alert("サブクラスでちゃんと実装してね。");
},
/**
* pathにリクエストを出して、読み込みが終わったら、completeメソッドを呼ぶ。
*
* @param path : リクエスト先なのだ。当然のことながら、同じサーバのみね。
*/
get: function() {
new Ajax.Request(this.path,
{
method : 'get',
onFailure : function(request) {
alert("ネットワークへの接続が失敗しました。");
},
/** 最後にbindAsEventListenerをちゃんとつけること。 */
onComplete : function(request) {
var result = request.responseText;
this.complete(result);
}.bindAsEventListener(this, false)
});
},
/**
* 親クラスでは、誰が何と言おうが、holderは、id=result_pである!
*/
set_holder: function(holder) {
this.holder = $('result_p');
},
complete: function(result) {
alert("サブクラスで、ちゃんと実装してね。");
}
}
/**
* AjaxParentクラスのサブクラス。
*/
var AjaxChild_A = Class.create();
Object.extend(AjaxChild_A.prototype, AjaxParent.prototype);
Object.extend(AjaxChild_A.prototype, {
/**
* 子クラスでinitializeを上書き。
*/
initialize: function(path) {
this.path = path;
alert("AjaxChild_A initialized....");
},
/**
* フィールド
*/
field: "this is field From AjaxChild_A",
/**
* 子クラスで、set_holderを上書き。これは、AjaxChild_Aのみ。
*/
set_holder: function(holder) {
this.holder = $(holder);
},
/**
* 子クラスで、completeを上書き。
* @param response
*/
complete : function(result) {
new Insertion.Top(this.holder, "AjaxChild_A: " + result + "<br />");
alert("AjaxChild_A : " + result);
}
});
/**
* AjaxParentクラスのサブクラス。
*/
var AjaxChild_B = Class.create();
Object.extend(AjaxChild_B.prototype, AjaxParent.prototype);
Object.extend(AjaxChild_B.prototype, {
/**
* 子クラスでinitializeを上書き。
*/
initialize: function(path) {
this.path = path;
alert("AjaxChild_B Initialized....");
},
/**
* フィールド
*/
field: "this is field From AjaxChild_B",
/**
* 子クラスで、completeを上書き。
* @param response
*/
complete : function(result) {
new Insertion.Top(this.holder, "AjaxChild_B: " + result + "<br />");
alert("AjaxChild_B : " + result);
}
});
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
/**
* createの引数typeによって、どちらの子クラスを呼ぶかを変える。
*/
var AjaxController = Class.create();
AjaxController.factory = function(type, path, trigger) {
var my_ajax = eval('new AjaxChild_' + type +'("'+path+'")');
Event.observe($(trigger), 'click',
my_ajax.get.bindAsEventListener(my_ajax), false);
return my_ajax;
}
sample_ajax.html
<?xml version="1.0" encoding="shift_jis"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html lang="ja" xml:lang="ja" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="prototype.js"></script>
<script type="text/javascript" src="sample_ajax.js"></script>
<script language="JavaScript" type="text/JavaScript">
Event.observe(window, 'load', main, false);
function main() {
/**
* インスタンスを作ってやってみよう!
*/
var ajax_test = AjaxController.factory('A', './test_a.txt', 'trigger_a');
/**
* ちゃんと子クラスのフィールドにもアクセスできる。
*/
alert(ajax_test.field);
/**
* 同様に、メソッドにもね。
*/
ajax_test.set_holder('result_a');
/**
* インスタンスを作ってやってみよう!
*/
var ajax_test = AjaxController.factory('B', './test_b.txt', 'trigger_b');
/**
* ちゃんと子クラスのフィールドにもアクセスできる。
*/
alert(ajax_test.field);
/**
* メソッドは実装していないので、親のが呼ばれる。
*/
ajax_test.set_holder('result_b');
}
</script>
<title>Ajax Subclass Test</title>
</head>
<body>
<h1>Ajaxのテスト</h1>
<input type="button" id="trigger_a" value="Ajax_A!" />
<input type="button" id="trigger_b" value="Ajax_B!" />
<hr />
<h2>AjaxChild_Aが実装したのでこっち。</h2>
<div id="result_a"></div>
<h2>AjaxChild_Bは未実装なのでここは出力されない</h2>
<div id="result_b"></div>
<h2>AjaxParentのメソッドのままだが、AjaxChild_Bは未実装なのでこっち。</h2>
<div id="result_p"></div>
</body>
</html>
気になるところは、コメントに書いてみた。onCompleteにbindAsEventListenerをつけないと、thisの値が変わってしまう。これで、一度悩んだ。。。
拡張するときに、プロパティを書き換えるのもなんだか、嫌だけど、しゃーなし。
参考にしたのが次のページ。
■IT戦記
拡張の方法はここを参照させていただきました。prototype.jsと少し拡張の書き方が違うが、やっていることは一緒。prototype.jsでは、次のようにしていたりする。
Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
■naoyaのはてなダイアリー
ここを見て、動的にクラス名を決定するところで、evalを使うようにした。次のような感じ。
var test_class = eval('new ' + classname);
■llameradaの日記
■こども(てれび)
上の二つを見て、thisがどっかいっちゃうところを修正した。AjaxのonCompleteにbindAsEventListenerをくっつけるところは、ここで、勉強しました。
■Using prototype.js v.1.4.0
1.4.0を対象にしていたので。
(続きを読む...)