レベル: 中級 Brett D. McLaughlin, Sr. (brett@newInstance.com), Author and Editor, O'Reilly Media, Inc.
2008年 1月 15日 バックエンドの処理、つまりサーバー・サイドのスクリプトとプログラムは、必ずしも Ajax アプリケーションの中に組み込んでおけば適切に動作するとは限りません。むしろ、適切かつ効率的な形式でデータが送信されるように注意深く計画することで、アプリケーション全体を必要以上に複雑なものにせず、1 つにまとまったものにすることができるようになります。今回は Brett McLaughlin が、適切なサーバー・サイド・スクリプトによって Ajax の動作を補完できることを説明します。
このシリーズの第 1 回では、写真のギャラリーを表示するための視覚的にリッチなフロントエンドを、Nathan Smith による Hoverbox のコードをベースに作成しました (「参考文献」のセクションにはオリジナルの Hoverbox コードへのリンクがあります)。そのプロセスの中で、UI に関する基本原則をいくつか学びました。その原則には、目の動きを表す Z トラッキング・パターンや、ページに一貫性を持たせること、ページの下の方のブロックほどテキストのサイズを小さくすること、さらには serif フォントと sans-serif フォントの読みやすさの違いなどがありました。
第 1 回の記事が終わった時点で、素敵な、使いやすい画像ギャラリーができているはずです。前回の記事では、図 1 の段階で Hoverbox の UI の説明を終えました。
図 1. 前回の記事で使用した Hoverbox の UI
今回の記事では、重要なバックエンド処理と、このギャラリーをバックエンドに接続するための Ajax 固有のコードを追加します。
Ajax の配管作業を行う。
以前私が言ったように、Ajax の作業の大部分は配管作業のようなものです。つまり XmlHttpRequest オブジェクトを設定し、サーバー・サイド・プログラムを呼び出し、そしてレスポンスを取得します。プログラムはさまざまに異なり、またリクエストの詳細も変わるかもしれませんが、基本的な設定はどの状況でも同じであり、以下のようなものです。
- 新しいリクエスト・オブジェクトを (できればクロス・ブラウザーの方法で) 作成します。
- リクエスト URL と、場合によっては POST リクエスト・データを作成します。
- プログラムがサーバーからレスポンスを受け取ったときに、ブラウザーに対してコールバックをするためのメソッドを設定します。
- リクエストを送信します。
- コールバックを作成します (このコールバックは、プログラムがサーバー・データを使って行う必要のある、すべてのことを行います)。
これらの詳細は他のさまざまな記事で説明されています (そうした記事については「参考文献」セクションで再度触れます)。そのためこのセクションでは簡単な説明にとどめておきます。
レスポンス・オブジェクトを作成する
まず、XmlHttpRequest という種類のレスポンス・オブジェクトが必要です。これを、ブラウザーに依存しない方法で作成しましょう。それには、リスト 1 のようなコードが必要になります。
リスト 1. レスポンス・オブジェクトを作成する
/* Create a new XMLHttpRequest object to talk to the Web server */
var request = false;
/*@cc_on @*/
/*@if (@_jscript_version >= 5)
try {
request = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
request = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e2) {
request = false;
}
}
@end @*/
if (!request && typeof XMLHttpRequest != 'undefined') {
request = new XMLHttpRequest();
} |
私はこれを hoverbox-ajax.js というファイルに保存しました。このファイルは、この Hoverbox Web アプリケーションのすべての JavaScript を保存する場所です。次に、HTML の head 要素の中で、このファイルを参照する必要があります。
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<script language="JavaScript" src="hoverbox-ajax.js"> </script>
<title>Hoverbox Image Gallery</title>
<link rel="stylesheet" href='css/hoverbox.css' type="text/css"
media="screen, projection" />
<!--[if IE]>
<link rel="stylesheet" href='css/ie_fixes.css' type="text/css"
media="screen, projection" />
<![endif]-->
</head>
|
サーバー・サイドの仕様が必要です
この時点で、実際にサーバー・サイドのスクリプトに接続することができ、それぞれの写真に関する情報を取得することができます。しかしそのスクリプトの入力は何でしょう。また、出力はどんなフォーマットなのでしょう。話を少し現実的なものにするために、サーバー・サイドのコードのすべてをいじれるわけではない、としましょう。例えば、データを取得するスクリプトが既に作成されており、皆さんは単に Ajax 対応の新しいフロントエンドを作成しているだけなのかもしれません。あるいは、皆さんは PHP の担当ではなく、誰か他の人がそうしたことを扱っているのかもしれません。いずれにせよ、スクリプトが想定しているものは何か、そしてそのスクリプトとの通信方法を知る必要があります。
このアプリケーションと通信するスクリプトの仕様を非常に簡単に表現すると、以下のようになります。
 |
Ajax アプリケーションはサンドボックス化されています
XmlHttpRequest オブジェクトの中に組みこまれたセキュリティー機構の 1 つがサンドボックスです。簡単に言うと、これはつまり、指定されたドメイン (例えば newInstance.com など) 上で実行する JavaScript コードは、その同じドメインのスクリプト以外に対してリクエストを送ることはできない、という意味です。そのため、もしスクリプトがローカル・マシンで実行されている場合には、そのスクリプトは、そのローカル・マシン上 (おそらく、そのローカル・マシンの Apache や IIS などの Web サーバー上) で実行しているスクリプトに対してしかリクエストを送ることはできません。
それをこの記事の場合に当てはめると、皆さんの Web ページ上の JavaScript は newInstance.com 上のコードを呼び出すことができません。皆さんのページは私の Web サーバー上にないからです。皆さん自身の設定に合わせて、この記事で使用している URL を変更する必要があります。また、データベースにアクセスできない場合には、データベースを使わないようにサーバー・サイド・スクリプトを単純化する必要もあります (この先の何セクションかで詳細を説明します)。
|
|
- このスクリプトは特定の URL にあります。この記事では、http://www.newInstance.com/ajax/lookupImage.php を使います。
- このスクリプトの入力は 1 つのみ (参照対象の画像の名前) です。この名前にはパスも拡張子も付けません。そのため、例えば img/photo07.jpg のような画像の場合、このスクリプトは「photo7.jpg」を要求します。
- このスクリプトは、画像の名前、タイトル、データ、そして画像の説明を、すべてパイプで区切って返します。
通常なら、JavaScript に戻って作業をするにはこの 3 つの情報で十分なはずですが、実際のスクリプトを見ずに先に進むことのないように、少し回り道をして、この仕様に記述されている PHP スクリプト (そしてMySQL データベース) を実際に作成してみましょう。そうすれば、このアプリケーションを実際に皆さん自身のマシンで実行することができます。
ちょっとした PHP
アプリケーション (特に作成している JavaScript を組み込む対象となる Web アプリケーション) を設計する際に、対象となるデータベースや接続先のサーバー・サイド・スクリプトがどう振る舞うのかを判断しなければならないことは非常に稀です。多くの場合は、仕様、あるいは一連のサンプル入力が与えられ、そのフォーマットに従って作業を行います。
ここでは、そうした状況をある程度エミュレートするために、Web フォームがどう設計されるかをあまり考慮せず、簡単な PHP スクリプトを作成します。これは非常に現実的なケースだと思います。つまり、誰かが皆さんにスクリプトの作成を任せたり、あるいは少なくともそのスクリプトの動作の詳細の作成を任せたりするのに、皆さんには大した情報がないのです。でも、それでも問題ありません。皆さんは Web には詳しいので、たとえ非常に奇妙なデータ・フォーマットであっても、それをどう扱えばよいかを知っているからです。
PHP スクリプト
これは実際にはクライアント・サイドに関することであり、皆さんは誰かからサーバー・サイドの仕様を渡されただけ、という前提なので、リスト 2 をサーバー用の PHP とします。これを詳しく調べることもでき、完全に無視することもできます。とにかくこのスクリプトが Web ページと同じサーバーのどこかで実行されていることを確認し、このスクリプトにアクセスするための JavaScript を作成できるようにします。
リスト 2. lookupImage.php のスクリプト
<?php
// Connect to database
$conn = @mysql_connect("dc1-mysql-01.kattare.com", "bmclaugh", "db-1p0j0rdw");
if (!$conn)
die("Error connecting to MySQL: " . mysql_error());
if (!mysql_select_db("bmclaugh", $conn))
die("Error selecting database: " . mysql_error());
$image_name = $_REQUEST['image'];
$select = 'SELECT *';$from = ' FROM image_database';
$where = ' WHERE name = \'' . $image_name . '\'';
$queryResult = @mysql_query($select . $from . $where);
if (!$queryResult)
die("Error retreiving image data from the database.");
while ($row = mysql_fetch_array($queryResult)) {
echo $row['name'] . "|" .
$row['title'] . "|" .
$row['date'] . "|" .
$row['description'];
}
mysql_close($conn);
?> |
このスクリプトは基本的に、画像の名前が含まれたリクエスト・パラメータを取得し、データベースの中でそのパラメーターを検索し、そしてその画像に関するすべての情報を、(仕様に記述されているように) パイプ ( | ) で区切って返します。
そして、ちょっとした SQL
これをもう少し現実的にするために、(設定が少し複雑になりますが) 各画像に関する情報を保存する SQL データベースを作成しましょう。以下に示すのは phpMyAdmin で私が使用しているテーブルのスクリーンショットです (図 2)。
図 2. サンプル・データベースのテーブルの構造
この場合の列は非常に単純です。
-
name: 画像の名前。これは HTML の各
img 要素の src 属性の中で使っているファイル名と一致します。このすべての画像ファイルにアクセスする際には、img/ という接頭辞 (各画像が保存されているディレクトリーの名前) を削除する必要があることに注意してください。そのため、img/image_01.jpg として参照される画像の名前は「image_01.jpg」となります。
-
title: 画像のタイトル (例えば「Sunrise Over the Bay (湾からの日の出) など」。このデータは、Web ページの右側部分で各画像に対して表示される一番大きなヘッダーです。
-
date: 容易にわかると思いますが、その画像が撮影された日付です (ただし、必ずしも画像がデータベースに保存された日付ではありません)。
-
description: 各画像の主な内容を表す、画像に関する長い説明。
お断りしておきますが、このテーブル設計は非常に初歩的な設計であり、素晴らしい設計と言えるものではありません。画像名をキーとして使うのは最良の考えではなく、他にも改良すべき部分はたくさんあります。しかしそれは、データベースの設計に関する記事で扱う話題であり、この記事でのポイントは、「実際の」アプリケーションで通常扱うことになる、Web ページから JavaScript、JavaScript からサーバー・サイド、そしてデータベースへ、という情報のフローをセットアップすることです。
 |
Blob 型はうまくエクスポートできません
私はこのデータベースで BLOB 型を使いましたが、エクスポートを行うとバイナリー・データとして出力されます (バイナリー・データは元々理解できないものです)。そのため、SQL データ・ファイルの中におかしなフォーマットがあっても、設定を直したりしないでください。
|
|
サンプル・データを挿入する
次に、テーブルの中にサンプル・データを挿入する必要があります。「参考文献」セクションには、テーブルを作成し、5 行のデータを挿入する、ダウンロード可能な SQL バッチ・ファイルを含めてあります。これを皆さん自身のデータベース用のデータとして自由に使ってください。自分が撮影したものではない 20 枚もの写真の説明を入力する作業は、午後の時間を楽しく過ごすための方法としてはふさわしくないはずです。このサンプルには 5 行のデータが含まれていますが、もちろん、さらにサンプル・データを追加し、このギャラリーの残り部分を埋めることもできます。
テーブルの中にデータが入ると、フロントエンド (Web フォーム) とバックエンド (データベース) とを実際につなぎ合わせる準備が整ったことになります。
リクエストを送信する
これで、Web ページには (request という) リクエスト・オブジェクトが用意でき、PHP スクリプトと、データを取得しにいく対象となるデータベースも用意できました。今度は、そのスクリプトに対してリクエストを送信する JavaScript 関数を作成し、ギャラリーの画像をその関数に接続します。
最初にスケルトン関数を作成する
クライアントとサーバーとの接続を処理する前に、画像から関数を呼び出せることを確認する必要があります。そこで、JavaScript による簡単なプレースフォルダー関数から始めることにしましょう。
function getImageDetails() {
alert("Image details would get pulled here.");
}
|
この関数を、リクエスト・オブジェクトを作成するコードのすぐ下の、hoverbox-ajax.js に置きます。この関数は実際には単なるプレースフォルダーにすぎませんが、こうすることで、この関数を呼び出すことができ、まだサーバー・サイドと Ajax の詳細を処理する必要がありません。この関数はまずリクエスト・オブジェクトを作成し、次に情報メッセージ・ボックスをポップアップします。
画像の HTML と CSS を詳しく見る
今度は、画像の HTML を変更する必要があります。ギャラリーの各画像がどのように表現されているかを詳しく見てみましょう。
<li>
<a href="#"><img src="img/photo01.jpg" alt="description" />
<img src="img/photo01.jpg" alt="description" class="preview" /></a>
</li>
|
この HTML は、少し見ただけでは混乱するかもしれませんので、詳しく見ていきましょう。まず、a タグがありますが、このタグにはリンク先がありません (# 記号をリンクの対象として使っています)。こうすることで、画像の上でマウスを動かしたときに CSS ルールを適用させています。次に img タグがあります。これが、デフォルトでギャラリーに表示される画像、つまり小さなサイズの画像です。最後に 2 番目の img があり、「preview」というクラスが指定されています。このクラスの CSS のうち、ここで関係してくる部分は以下のとおりです (これは css/hoverbox.css からの抜粋です)。
.hoverbox a
{
cursor: default;
}
.hoverbox a .preview
{
display: none;
}
.hoverbox a:hover .preview
{
display: block;
position: absolute;
top: -33px;
left: -45px;
z-index: 1;
}
|
この CSS に記述されている内容は、デフォルトで、この 2 番目の画像 (リサイズされていない、従って大きなサイズのギャラリー画像) は隠れている、ということです (display プロパティーが none に設定されています)。そのため、このページがロードされたときに、この 2 番目の画像タグで参照される画像は見えません。
しかし、2 番目の画像タグで参照される画像の上でマウスを動かすと、.preview ルールが有効になります。その画像は (2 番目の画像の z-index は非常に小さい値である 1 に設定されているため) 最初の画像の上に表示され、しかも少し上に動くため、下にある画像を完全に覆います。この効果を図 3 に示します。
図 3. 大きな画像が下にある画像を覆う
JavaScript スケルトン関数を呼び出す
ここで必要な動作は、ユーザーのマウスが画像の上で動いたときに JavaScript ハンドラーを呼び出すことです。つまり、すべての img タグに対して以下のようにする必要があるということです。
<li>
<a href="#"><img src="img/photo01.jpg" alt="description"
onmouseover="javascript:getImageDetails();" /><img src="img/photo01.jpg"
alt="description" class="preview" /></a>
</li>
|
これを 20 個の画像タグすべてに追加し、ページをリロードします。ではページをリロードしたら、よくページを調べてみてください。いかがでしょうか。図 4 は、この設定の実際を示しています。
図 4. マウスオーバー・イベントでアラートがポップアップする
これはとても邪魔だと思われるのではないでしょうか。その原因の 1 つはアラートの使い方です。マウスが画像の上を動くたびにアラートがポップアップするため、そのたびに OK をクリックしなければなりません。しかもこれは、言うまでもなく HTML の中の 20 個の img タグをすべて変更してハンドラーを追加する、という手間をかけた挙げ句の結果なのです。
しかし、もっと大きな問題は、使いやすさの問題です。最終的に、getImageDetails() 関数はマウスオーバー・イベントごとにサーバー・サイド・スクリプトを呼び出さなければなりません。したがって、2 列目の 3 番目の画像まで下がってズームする場合でも、マウスが画像の上を通るたびにサーバーにアクセスすることになります。これはとんでもないことです。処理オーバーヘッドが多すぎ、しかもその処理は必要ないのです。
画像の詳細の処理をクリックに移す
もっと適切な方法は、大きな画像 (「preview」クラスを持っています) の onclick イベントを使い、ギャラリーの中の画像がクリックされた場合のみサーバーから詳細を引き出すという方法です。しかしそれは、20 枚の画像からマウスオーバー・ハンドラーを削除し、新しいハンドラーをさらに 20 枚の画像の中に追加するということです。これでは非常に面倒なので、少し戻って、これを修正しましょう。その際に、大部分の Ajax アプリケーションが非常に動的であり、HTML が大きく変化しても影響されない、ということを念頭に置いてください。
以下に示すのは、ページ上のすべての img タグを調べ、特定の CSS クラス (「preview」) を持つすべての画像を見つけるための、単純な JavaScript 関数です (この関数を、他のすべての JavaScript と同じく hoverbox-ajax.js に置きます)。これで、各画像の onclick ハンドラーは getImageDetails メソッドを指しています。これで完璧です。
function addImageHandlers() {
var imagesDiv = document.getElementById("images");
var imageElements = imagesDiv.getElementsByTagName("img");
for (var i=0; i<imageElements.length; i++) {
var class = imageElements[i].className;
if (class == 'preview') {
imageElements[i].onclick = getImageDetails;
}
}
}
|
この関数を実行するためには、ページの body 要素の onLoad ハンドラーの中にこの関数を組み込みます (下記)。
<body onLoad="addImageHandlers();">
|
これはとても標準的な「Ajax 型」パターンです。つまりプログラムでイベント・ハンドラーを追加しており、HTML の中に手動で追加しているわけではありません。この大きな利点として、容易に変更を行うことができ、コードの中の 20 枚 (または 40 枚とも言えます) の画像要素すべてに触れなくてもよいことです。
再度ページを実行してみると、今度は画像をクリックしないとアラート・ボックスがポップアップしないことに気付くはずです。この方がずっと適切です。
クリックされた画像を判断する
次に、クリックされた画像の名前を JavaScript 関数を使って判断し、その名前が PHP サーバー・サイド・スクリプトが想定するフォーマットに合っていることを確認する必要があります。画像のフル・パスを関数に取得する部分は簡単です。これは、どの JavaScript 関数が呼び出された場合も、その関数を呼び出したのはページのどの要素か、ブラウザーにはわかるためです。その要素にアクセスするためには、this キーワードを使います。
この動作を調べるために、getImageDetails() メソッドを以下のように変更します。
function getImageDetails() {
createRequest();
alert(this.src);
}
|
this はこの関数を呼び出した画像要素を参照し、また src 属性によって画像のソース属性がわかります。これらの変更を行ってページをリロードすると、図 5 のような表示が現れるはずです。
図 5. 今度はアラートが画像の src 属性を表示します
これは、正しい方向に向かっての大きなステップです。これでギャラリーは JavaScript 関数を呼び出すようになり、画像のフル・パスを取得できるようになりました。
画像からパス情報を削除する
サーバー上の PHP スクリプトを呼び出すために必要なステップは、あと 1 つのみです。そのステップというのは、パス情報や拡張子を何も付けずに、画像のパスを 1 つの名前 (写真の名前) にすることです。そこで、例えば「file:///Users/bmclaugh/Documents/developerworks/ajax_2-backEnd/hoverbox/img/photo05.jpg」の場合であれば、「photo05」のみを PHP スクリプトに送信する必要があります。これは Ajax 関連の課題ではなく、JavaScript の演習であることがわかります。そこで、以下のコードはこのための、そのまま使えるコードです。
function getImageName(imagePath) {
var splitPath = imagePath.split('/');
var fileName = splitPath[splitPath.length - 1];
return (fileName.split('.'))[0];
}
|
この関数は画像のパスを調べ、画像の名前のみを取得します。そこで今度は元に戻り、getImageDetails() 関数を少し更新します。
function getImageDetails() {
createRequest();
alert(getImageName(this.src));
}
|
保存してリロードすると、ついに求めていたものが得られます。つまり画像名を取得し、それを PHP サーバー・サイド・スクリプトに送信できるハンドラーが得られたのです。図 6 は、この段階での動作の様子を示しています。
図 6. 画像をクリックすると画像名を取得でき、完璧です
サーバーに対してリクエストを送信する
今度は、画像名を PHP スクリプトに送信する、という簡単な作業です。これを実現するためには、Ajax の基本操作が少しばかり必要です。
function getImageDetails() {
createRequest();
var url = "lookupImage.php?image=" + escape(getImageName(this.src));
request.open("GET", url, true);
request.onreadystatechange = showImageDetails;
request.send(null);
}
|
これは、今まで作業してきたものと同じ関数ですが、いくつか明らかな変更が加えられています。ここでは PHP スクリプトの URL が作成されており、画像名が付加されています (途中でエンコーディングのおかしな問題が起こらないように、エスケープされています)。そしてリクエストがセットアップされ、コールバック関数が割り当てられて、リクエストが送信されます。この前のセクションで作成した JavaScript 関数が既にすべての作業を行ってくれたので、これですべてです。
 |
Ajax の経験が必要です
この記事は、Ajax に関して基本的な経験があり、また Ajax に慣れている読者を前提にしています。もしそうでない場合は、「参考文献」セクションを調べてみてください。「Ajax をマスターする」シリーズは Ajax に関する基本をわかりやすく説明しており、この記事のアプリケーションを理解できるレベルにまで読者を引き上げてくれる内容となっています。
|
|
サーバーのレスポンスを処理する
Ajax アプリケーションで面倒なことの 1 つが、アプリケーションが何箇所にも広がっていることです (つまり HTML ページ、スタイル設定と単純な動作 (ギャラリーの中で大きな画像をポップアップさせる、など) のための CSS、クライアント上の JavaScript、サーバー上の PHP、等々)。こうしたアプリケーションのデバッグは容易ではありません。
そのため、ほとんどの場合は 1 度に 1 つの部分のみに対して作業した方が容易であり、また適切です。例えば、サーバーのレスポンスを受信してデコードし、その内容をページ内に表示するコールバック関数を作成するよりも、単純にサーバーのレスポンスをエコー・バックし、そのレスポンスが想定どおりのものであることを確認した方が容易です。その後で、クライアント・サイドの動作を追加するのです。それを念頭に置いた上で、以下にコールバック関数の先頭を示しています。
function showImageDetails() {
if (request.readyState == 4) {
if (request.status == 200) {
var response = request.responseText;
alert(response);
}
}
}
|
この関数の名前が、先ほど getImageDetails() 関数の中でリクエスト・オブジェクトに対して指定した名前と一致しなければならないことを思い出してください。
これを試してみると、図 7 に示すレスポンスを受信できるはずです。(この図は、データを MySQL データベースにロードした場合、あるいは PHP スクリプトがダミー・データを返すように変更した場合を想定しています。)
図 7. 画像をクリックすると、今度はその画像のデータが返されます
うまく動作しているようです。データを取得できたので、今度はこのデータを分解し、Web フォーム上の適切な場所に置けばよいだけです。
サーバーからのデータを分解する
最初に必要なことは、サーバーからのデータを分解することです。そのためには JavaScript の split() 関数を使います。
function showImageDetails() {
if (request.readyState == 4) {
if (request.status == 200) {
var response = request.responseText;
var splitResponse = response.split('|');
var title = splitResponse[1];
var date = splitResponse[2];
var description = splitResponse[3];
}
}
}
|
split() はストリングを複数の部分に分解し、配列に保存します。この関数によって、画像のタイトル、日付、そして説明を取得できるようになります。(split() が要素ゼロから始まる配列を返すことに注意してください。この場合、splitResponse[0] は画像の名前を返しますが、これは元々サーバーに送信されたものです)。
Web ページに ID を追加する
id 属性を使って、Web ページ上の要素に直接アクセスする方法が最も簡単です。Web ページの、画像の詳細のセクションに以下の ID を追加します。
<div id="details">
<h2 class="info-title" id="info-title">Sunrise over the bay</h2>
<h3 class="info-date" id="info-date">27 October, 2006</h3>
<p class="info-text" id="info-text">Here is what I experienced when I took this photo.</p>
</div>
|
適切な要素を取得する
(要素のテキストを変更する準備として) これらの要素にアクセスすることは、非常に簡単です。そのためには、各要素に対して getElementById() を使います。
function showImageDetails() {
if (request.readyState == 4) {
if (request.status == 200) {
var response = request.responseText;
var splitResponse = response.split('|');
var title = splitResponse[1];
var date = splitResponse[2];
var description = splitResponse[3];
var titleElement = document.getElementById("info-title");
var dateElement = document.getElementById("info-date");
var descriptionElement = document.getElementById("info-text");
}
}
}
|
とても単純です。これで、あとは実際にこれらの要素のテキストをサーバーのデータと置き換えるだけです。
テキストを置き換える
Web ページ上の要素のテキストを変更する作業は、容易なはずだが実際には非常に面倒という種類の作業の 1 つです。DOM (Document Object Model) はテキストを、そのテキストを含む要素の子ノードとして保存するため、話は複雑になります。例えば、p の中のテキストは、実際には、その p を表す要素ノードの子であるテキスト・ノードに保存されます。
さて、showImageDetails() 関数のための作業を終える前に、DOM での作業を容易にするためのユーティリティー関数が少し必要です。これらのユーティリティー関数によって、ノード内のテキストをクリアーすることができ、新しいテキストを挿入することができます。以下の関数を両方とも hoverbox-ajax.js ファイルに追加します。
function replaceText(el, text) {
if (el != null) {
clearText(el);
var newNode = document.createTextNode(text);
el.appendChild(newNode);
}
}
function clearText(el) {
if (el != null) {
if (el.childNodes) {
for (var i=0; i<el.childNodes.length; i++) {
var childNode = el.childNodes[i];
el.removeChild(childNode);
}
}
}
}
|
便利なことに、これらの関数をすべての JavaScript ファイルに入れることができ (つまり dom-utils.js または text-utils.js のようなファイルの中に組み込んでおくことができ)、またすべてのアプリケーションで使用することができます。
今度は showImageDetails() メソッドに以下のようにいくつかの簡単な追加を行い、それで終了です。
function showImageDetails() {
if (request.readyState == 4) {
if (request.status == 200) {
var response = request.responseText;
var splitResponse = response.split('|');
var title = splitResponse[1];
var date = splitResponse[2];
var description = splitResponse[3];
var titleElement = document.getElementById("info-title");
var dateElement = document.getElementById("info-date");
var descriptionElement = document.getElementById("info-text");
replaceText(titleElement, title);
replaceText(dateElement, date);
replaceText(descriptionElement, description);
}
}
}
|
最終的なテスト
すべてを保存し、すべてをリロードすると、とても幸せな光景が展開されます。つまり、実際に動作する非同期の画像ギャラリーが表示されるのです。図 8 は、私のギャラリーが実際に表示される様子を示しています。
図 8. 完成した画像ギャラリー
これにさらに変更を加え、さらに細かく調整することもできます。例えば、画像の右側の列が少しテキストに重なっていることがわかります。そこで、ギャラリーとテキストの間隔を広げるとよいかもしれません。また、ロケールに合わせて日付のフォーマットを変更したり、あるいはもっと意匠を凝らして、画像の取得源としてブラウザーがレポートするロケールに基づいて日付をフォーマットしたりすることもできます。そしてもちろん、この記事のサンプル・データは 5 枚の画像の分しか提供していないので、他の 15 枚の画像のデータを追加することもできます。可能性は無限です。
Ajax に必要なものは技術ではありません
この記事はミニ・シリーズの 2 回目ですが、非常に見事なちょっとした Ajax アプリケーションを作成することができました。しかし、この記事の大部分では、send() や setRequestHeader() などの XmlHttpRequest の呼び出し以外の部分に焦点を絞りました。実際これらの部分は、経験を重ねたほとんどの Ajax 開発者が認識している「(素晴らしい Ajax アプリケーションにするための) 泥臭いけれどもちょっとした秘訣」なのです。Ajax に要求される技術は非常に単純です。ちょっとした JavaScript があればよく、しかも作業を容易にしてくれる Dojo や Prototype などの便利なライブラリーすら使わなくても、おそらく 90% 程度を完成させることができます。少し DHTML を使い、場合によっては DOM でも使用すれば、それでプロなのです。ただしこれは、技術面での話です。
優れた Ajax 開発者であるかどうかが本当にわかるのは、アプリケーションとそのユーザー・インターフェースの各部分をどう処理するかにかかっています。アプリケーションのルック・アンド・フィールはどのようなものでしょう。(前回の記事で、Ajax アプリケーションでは使いやすさが鍵であることを説明したことを思い出してください。) サーバー・サイドのコンポーネントは、最小限のデータ量を、使いやすいフォーマットで提供するでしょうか。それとも、Ajax コードはデータと悪戦苦闘しなければならず、本来は迅速で俊敏な動作をするはずのインターフェースの速度を低下させてしまうでしょうか。また、非同期動作を適切に利用しているでしょうか。このアプリケーションでは、クリックしない限りデータを取得しないようにアプリケーションを変更し、マウスによってズームされる画像ごとにデータを取り出さずにすむようにしました。これは使いやすさの好例です。つまり、必要であれば、情報はそこにあります。しかしユーザーがそのデータをどう処理するかについての想定はしませんでした。
 |
developerWorks の Ajax リソース・センター
Ajax resource center にアクセスしてください。ここは Ajax アプリケーションを開発するための無料のツールやコード、そして情報が豊富に用意されたワンストップ・ショップです。Ajax のエキスパートである Jack Herrington がホストする活発なコミュニティー Ajax forum では、皆さんが今まさに求めている答え持っている可能性のある仲間と出会うことができます。
|
|
要するに Ajax では、純粋な技術よりも、むしろ設計とアーキテクチャーが重要なのです。Ajax の実際は、developerWorks の他のシリーズで学ぶことができます (私自身の書いた、12 回にもわたる「Ajax をマスターする」シリーズもあります)。しかし Ajax アプリケーションの成功に必要なものは、UI 設計、適切なユーザー・テスト、そして明確な考え方などの狭間にあるものなのです。Ajax アプリケーションの代表例である、Google マップの大部分の実装には真の非同期動作はなく、インターフェースの「Ajax らしい」部分を処理するコードは比較的単純です。しかし、インターフェースには何千 (何百万?) 時間というマンパワーが費やされ、画面上のどこに情報を置くか、どのようなオプションを利用できるか、そしてそれらをどのようにコントロールするかが検討されています。これらは Ajax 技術の問題ではありませんが、どれもすべてアプリケーションに影響します。
まとめ
この 2 回シリーズの記事を終わるにあたって、少し時間をかけ、このアプリケーションのユーザー・インターフェースを調整してみてください。テキスト情報を左に移動すると、アプリケーションの印象はどうなるでしょう。画像の詳細を表示するために、その画像をクリックする必要があるとしたらどうでしょう。そして全体的な印象はどう変わるでしょう。また、サーバー・サイドのコンポーネントもいじってみてください。より多くの情報、あるいはより少ない情報を返すようにしたらどうでしょう。その違いはわかるでしょうか。
こうした単純な例であっても、十分時間をかけていじってみると、アプリケーションを「不細工な」ものではなく「使いやすい」ものにするためには何をすればよいのか、より適切な感覚をつかめるはずです。失礼に当たることが心配なので、大量に存在している不細工なオンライン・サイトをリストすることは差し控えますが、ネット・サーフィンをしてみれば、そうしたサイトが山ほど見つかるはずです。なぜそうしたサイトは不細工な印象を与えるのでしょう。そこからどんな教訓が得られるでしょう。それらを考えながら進めれば、驚くような独自の Ajax アプリケーションをすぐに開発できるようになるはずです。
ダウンロード | 内容 | ファイル名 | サイズ | ダウンロード形式 |
|---|
| Sample application | wa-aj-backendsamples.zip | 280KB | HTTP |
|---|
| Sample application | wa-aj-backendhoverbox.zip | 282KB | HTTP |
|---|
| Sample application | w-aj-backendsampleData.sql.txt | 12KB | HTTP |
|---|
参考文献 学ぶために
-
このシリーズの第 1 回は、驚くような独自の Ajax アプリケーションを作成するための第一歩を説明しています。
- この記事のサンプル・アプリケーションのベースとして使用した Hoverbox の資料を調べてください。
- Hoverbox のオンライン・デモを見ると、このサンプル・アプリケーションの出発点を確認することができます。
- この記事で説明した方法を、さらに巧妙な JavaScript ツールキット、Lightbox に適用してください。
- developerWorks の Ajax resource center には、今すぐにクールな Ajax アプリケーションの作成を開始するために役立つツールやコード、情報が豊富に用意されています。
- 開発者の間で Web 2.0 がホットな領域であることを考慮して、Web development ゾーンのリソースはより一層充実したものになっています。
製品や技術を入手するために
議論するために
著者について  | 
|  | Brett McLaughlin は Logo の時代からコンピューターの仕事をしています (あの小さな三角形を覚えていますか)。最近では、彼は Java と XML のコミュニティーで最もよく知られた著作者兼プログラマーの 1 人になっています。彼は Nextel Communications and Allegiance Telecom, Inc. で複雑なエンタープライズ・システムの実装に携わり、Lutris Technologies では実際にアプリケーション・サーバーを作成し、そして最近では、O'Reilly Media, Inc. にて、重要な話題に関する本の執筆や編集を続けています。著書『Head Rush Ajax ― 学びながら読む Ajax 入門』では、賞を獲得した革新的な Head First 手法を Ajax に導入しています。『Java 5.0 Tige』は、最新バージョンの Java 技術に関する最初の本でした。そして彼の古典作『Java & XML』は、Java 言語での XML 技術の使い方に関する決定作の地位を保っています。 |
記事の評価
|