GANCHIKU.com

AjaxのonCompleteの処理は、サブクラスに任せる。

そんなことをやってみたので、簡略化して、載せてみる。
で、ファイルは以下のような感じ。面倒なので、全部同じディレクトリにしてみた。
HTMLファイルを見れば、わかるが、prototype.jsを読み込んでから、sample_ajax.jsを読み込む。
おそらく、世間一般に広まっているprototype.js1.3.1では、動かない。まぁ、そんな感じ。

サンプルは「ここ」のページにあります。

  1. sample_ajax.js(下のソース)
  2. prototype.js(1.4.0)
  3. HTMLファイル(sample_ajaxhtml)
  4. Aの読み込み
  5. 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を対象にしていたので。

thisがどっかいっちゃう件を修正したぜ。
onComplete : funciton() {
}.bindAsEventListener(this, valse)をくっつければいいのね。
当然と言えば、当然だが、ようやく、bindの使い方がわかって目から鱗。

AjaxのonCompleteの処理は、サブクラスに任せる。 への2件のコメント

  1. Ryo より:

    りょうと申します。
    onComplete で指定したハンドラで this がとれなくて苦しんでいたところ、このブログを発見しました。
    超助かりました!!ありがとうございました!!!

  2. shin より:

    りょうさん

    おぉ。助けになりましたか。それはよかったです。私もJavaScriptのthisの挙動はちょっとひっかかりますが、当然と言えば当然なんですね。
    ただ、Eventと関係ないのに、bindAsEventListenerとしているところが非常に気になります。

    bindを使えばいいという噂もありますが、IEで問題があると聞いていますので、bindAsEventListenerを使用しています。
    なお、bindAsEventListenerの第二引数はいらないですね。。

    onCompleteのみならず、eachなどのiterator関数を使うときもthisがどっかいっちゃうので、bindしないといけないので、気を付けてください。

コメントをどうぞ

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Shin Ohno 2003-2012