AJAX で、動的にテーブルを作る方法(中・上級)

先のエントリーAJAX で、動的にテーブルを作る方法(初級)では、感じをつかむために、ベタにテーブルを作成していたため、重複するロジック/コードが多かった。ここではそれをフレームワークっぽくした。こういう軽量なコードを理解した上で、ひな型として自分で持っておくと見通しがよくてよいと思う。

この JavaScript ではできるだけ Java のアプレットにならった構造やメソッド名に近づけた。つまり、

  1. 基本メソッドは、
    • createXMLHttp …xmlhttp オブジェクトを作成する。
    • get …サーバと HTTP 通信する。
    • repaint …サーバから来た XML データを使って画面を書き換える。
    • create …最初の1回だけ画面を作る。
    • init …この JavaScript の呼び出しもとの HTML から呼ばれる。
    • setTemplate …サーバから得られた XML データが表示される部分を作成する。下の例を元にカスタマイズする
    • update …サーバから得られた XML データを setTemplate で作成した id に埋め込む。下の例を元にカスタマイズする
  2. 基本プロパティは定数の場合はすべて大文字で表し、配列には英単語の複数形「s」を付けることにした。
    • INTERVAL …AJAX での通信間隔(ミリ秒)
    • OBJECT …XML データ中で、たとえば ~ イテレーションの中の タグ。その場合は OBJECT = 'book'; と、タグ名を指定する。
    • TAGS(配列) …たとえば、book タグに含まれる要素である title、author、publisher タグ
    • LABELS(配列) …テーブルのヘッダのカラムで表示したい内容
    • TH_ALIGNS(配列) …テーブルで、左から順に各カラム中のヘッダの位置
    • TD_ALIGNS(配列) …テーブルで、左から順に各カラム中のデータ位置
    • URL …AJAX で通信する URL
  3. こうすると自分で実装(カスタマイズ)する部分、すなわちメソッドは
    • setTemplate …テーブルの元となるテンプレート HTML を吐くようにする。
    • update …INTERVAL 間隔で呼び出され、テーブルのデータを更新するようにする。
    …の 2つだけでよい。

以下はこのスクリプトを呼び出す HTML 部分の例。

2007/01/10 追記:

IE では、DIVタグに付けた ID を JavaScript から利用する場合は、JavaScript の前に DIV を宣言しなければならないらしい。document.getElementByID(...) is null or not an object というエラーが出る。Firefox だとその順番は関係がない。
また、document.getElementByID(DIV_DATA).insertBefore(table, null); は、IE だと table オブジェクトに tbody オブジェクトを追加してからでないとダメらしい。

<script src="https://<font color="red"><strong>your</strong></font>domain.com/your_javascript.js" type="text/javascript"> </script> <script type="text/javascript">yourdomain.com/your_server_process.php'; var DIV_DATA = 'data'; init(); // --></script>

動的なテーブルを作る、よりジェネリックな JavaScript は次の通り。このフレームワークでは setTemplate には何を書いてもよいが、ここでは table オブジェクトを作成することにより、HTML 中で id="data" に埋め込まれる部分にテーブルを当てはめている。また、テーブルを作成すると同時に各カラムに id="タグ名+数字" として、後に update メソッドで XML から抽出したデータを当てはめている。

//<![CDATA[ var isInitialized = false; var isLock = false; function createXMLHttp() { try { <pre>return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {
try {
  return new ActiveXObject('Microsoft.XMLHTTP');
} catch(e1) {
  try {
    return new XMLHttpRequest();
  } catch(e2) {
    return null;
  }
}
} } function create(xml) { isLock = true; setTemplate(xml); update(xml); isLock = false; } function init() { get(URL); setInterval("get('" + URL + "')", INTERVAL); } function repaint(xml) { !isInitialized ? create(xml) : update(xml); } function get(url) { if(isLock) return; var xmlhttp = null; if ((xmlhttp = createXMLHttp()) == null) {
window.alert("XMLHTTP Initialization Failed.");
} else {
xmlhttp.abort();
} xmlhttp.onreadystatechange = function() {
// readyState value
// 0: uninitialized / 1: loading
// 2: loaded /  3: interactive /  4: complete
if (xmlhttp.readyState == 4
&&  xmlhttp.status     == 200) { // 200 HTTP OK
  xml = xmlhttp.responseXML;
  repaint(xml);
}
} xmlhttp.open('GET', url + '&t=' + new Date(), true); // for avoiding IE's cache xmlhttp.setRequestHeader('Content-Type', 'text/html'); xmlhttp.overrideMimeType('text/xml'); // optional xmlhttp.send(null); } function update(xml) { if(xml) {
if(xml.documentElement) {  // for IE

  var objects = xml.documentElement.getElementsByTagName(OBJECT);

  for (var i = 0; i < objects.length; i++) {

    for (var j = 0; j < LABELS.length; j++) {

      var value = null;
      try {
        value = objects[i]
              .getElementsByTagName(TAGS[j])
              .item(0)
              .firstChild
              .nodeValue;
      } catch(e) {
      }
      switch(TAGS[j]) {
        case 'title':  // for example...
          value = '<strong>' + value + '</strong>';
          break;

        case 'author':  // for example...
        case 'date':
          value = value  ? value : 'n/a';
          break;
      }

      document.getElementById(LABELS[j] + i).innerHTML = value;

    } // End of for j
  } // End of for i
}
} } function setTemplate(xml) { if(xml) {
if(xml.documentElement) {  // for IE

  var objects = xml.documentElement.getElementsByTagName(OBJECT);

  var table = document.createElement('table');
  var tr, td, text;

  for (var i = -1; i < objects.length; i++) {

    tr = document.createElement('tr');
    for (var j = 0; j < LABELS.length; j++) {

      if(i < 0) {  // ヘッダ

        text = document.createTextNode(LABELS[j]);
        td   = document.createElement('th');
        td.setAttribute('style',  'text-align:' + TH_ALIGNS[j] + ';');
        td.setAttribute('valign', 'center');

      } else {

        text = document.createTextNode('');
        td   = document.createElement('td');
        td.setAttribute('style',  'text-align:' + TD_ALIGNS[j] + ';');
        td.setAttribute('valign', 'center');
      }

      td.insertBefore(text, null);
      tr.insertBefore(td,   null);
      td.setAttribute('id', LABELS[j] + i);
    }
    table.insertBefore(tr, null);

  } // End of for

  document.getElementById(DIV_DATA).insertBefore(table, null);
  isInitialized = true;
}
} } //]]>

Comments