japan.internet.com
japan.internet.com メンバーID
Twitter
Facebook
RSS
ピックアップ
2008年7月1日 10:00

Script.aculo.usのコントロールでWebアプリケーションをもっと使いやすく

はじめに

 筆者はDevXの以前の記事で、動的なWebアプリケーションの開発に役立つJavaScriptフレームワーク「Prototype」を取り上げましたが、その記事の最後で、PrototypeをベースにしたUIライブラリであるScript.aculo.usについて少し触れました。本稿ではScript.aculo.usが提供するオートコンプリータ、インプレースエディタ、スライダというWebコントロールについて説明します。

 Script.aculo.usは大きなライブラリなので、1つの記事で網羅的に説明することはできません。しかし、本稿の説明を読めば、Script.aculo.usのWebコントロールを利用してエンドユーザーエクスペリエンスを向上させることができるでしょう。

環境のセットアップ

 まずブラウザでPrototypeのホームページにアクセスし、最新バージョン(本稿の執筆時点では1.6.0.2)をダウンロードしてください。実際に必要なファイルは「prototype.js」だけです。次にScript.aculo.usをダウンロードします。ダウンロードページにアクセスし、最新バージョン(本稿の執筆時点では1.8.1)をダウンロードしてください。

 アーカイブを解凍し、「src」ディレクトリの下にあるファイルを「prototype.js」と一緒に適当なディレクトリの下に配置します。筆者は「scripts」ディレクトリの下に配置しました。以降の説明では、このディレクトリが何度も出てきます。

 この時点で、次のスクリプトファイルを次のようなコードを使って自分のページに組み込めば、Script.aculo.usのコントロールをアプリケーションで使用できるようになります。

<script type="text/javascript" src="scripts/prototype.js"></script>
<script type="text/javascript" 
   src="scripts/scriptaculous.js?load=effects,controls"></script>
 ご覧のように、エフェクトとコントロールの両方を組み込んでおく必要があります。このようにする理由は、コントロールがライブラリのエフェクト部分を内部的に使用するからです。

 環境が設定されたら、Script.aculo.usコントロールの世界がどのようなものか探索してみることができます。まずはオートコンプリータから始めることをお勧めします。これが最もよく使われるコントロールです。

''注''
 お気づきかもしれませんが、Script.aculo.usはPrototypeよりも高度にモジュール化されています。そのため、ライブラリの中の必要な部分だけを組み込むことができます。ただし、Script.aculo.usライブラリ全体を必要とする場合は、次の構文によって全体を組み込むことができます。
<script type="text/javascript" src="scripts/scriptaculous.js">
</script>

オートコンプリータ

 オートコンプリータがどのようなものかご存じない方は、WeeFlyのホームページにアクセスして実際の動作を確かめてみるとよいでしょう。WeeFlyは最新技術を利用した格安航空チケット&ホテル検索エンジンです。

 WeeFlyのトップページには2つのテキストボックスがあります。1つ目では出発空港、2つ目では到着空港を指定します。[Departure Airport]フィールドに、空港名を構成する文字列として少なくとも3文字を入力してください。その文字列が含まれている空港名のドロップダウンリストが表示されるはずです。図1は、「MIL」を検索文字列として指定したときの結果です。

図1 WeeFlyのDeparture Airportフィールドで使われているオートコンプリータ。このフィールドに少なくとも3文字(この例ではMIL)を入力すると、一致する空港名のリストが表示されます。
図1 WeeFlyのDeparture Airportフィールドで使われているオートコンプリータ。このフィールドに少なくとも3文字(この例ではMIL)を入力すると、一致する空港名のリストが表示されます。
 本稿を最後までお読みになれば、このようなオートコンプリータを作成できるようになります。

 既にお気づきでしょうが、オートコンプリータはテキストボックスと隠れた<div>とで構成されており、後者はユーザーがテキストボックスに3文字を入力すると表示されます。もちろん、オートコンプリータは<div>を表示する前に、ユーザーの要求に一致するアイテムのリストを用意しなければなりません。しかし、これらのアイテムをどのように取得するのでしょうか。基本的には、アイテムが存在する場所に応じて、次の2つの方法のいずれかを使用します。

  • アイテムがサーバー上にある場合は、Ajaxを使って取得します。
  • アイテムがクライアント上にある場合は、JavaScript配列内に取得します。
 次のページからは、具体的な方法を見ていくことにしましょう。

Ajaxベースのオートコンプリータの使用

 このタイプのオートコンプリータの動作は次のようになります。ユーザーが一定の文字数を入力すると、入力された文字列に一致するデータを取得するために非同期の要求を開始します。もちろん、サーバーサイドの処理を記述するための言語/テクノロジはJSP、サーブレット、ASP.NETなど、自分にとって都合のよいものを使ってかまいません。本稿ではPHPを使用します。

 Script.aculo.usを使用する場合、AjaxベースのオートコンプリータはAjax.Autocompleterクラスを使って作成できます。次に例を示します。

new Ajax.Autocompleter(
     'autoCompleteTextField',
     'autoCompleteMenu',
     'countries-list.php',
     {
          minChars: 1
     }
);
 コンストラクタに渡すパラメータは次のとおりです。

  • ユーザーが文字を入力するテキストボックスの名前
  • アイテムのリストが入る<div>のID
  • 要求の送信先となるサーバーサイドコンポーネントのURL
  • オートコンプリータのカスタマイズに使用できるオプションを示す、任意指定のリテラルオブジェクト(後述)
 まだよくわからなくても気にしないでください。次の例で、どのような仕組みになっているのか説明します。今回は国名リストのオートコンプリータを作成するものとします。これを達成するために必要なコードをリスト1に示します。

リスト1 国名リストのオートコンプリータ
<html>
  <head>
    <style type="text/css">
               div.auto_complete
               {
        width: 350px;
        background: #72f068;
        font-size: 9pt;
        color: #234e87;
        font-family: arial;
      }
      div.auto_complete ul
      {
        border:1px solid #888;
        margin:0;
        padding:0;
        width:100%;
        list-style-type:none;
      }
      div.auto_complete ul li
      {
        margin:0;
        padding:3px;
      }
      div.auto_complete ul li.selected
      {
        background-color: #234e87;
        color: #fff;
      }
      div.auto_complete ul strong.highlight
      {
        color: #800;
        margin:0;
        padding:0;
      }
    </style>

    <script type="text/javascript" 
      src="../scripts/prototype.js"></script>
    <script type="text/javascript" 
      src="../scripts/script.aculo.us.js?load=effects,controls">
      </script>
    <script type="text/javascript">
          function buildAutocompleter()
          {
               new Ajax.Autocompleter(
                    'autoCompleteTextField',
                    'autoCompleteMenu',
                    'countries-list.php'
               );
          }
          Event.observe(window, "load", buildAutocompleter);
    </script>
  </head>

  <body>
          <div>
               <label>Text field:</label>
               <input type="text" style="width: 300px;"
                 id="autoCompleteTextField"
                 name="autoCompleteTextField"/>
               <div id="autoCompleteMenu" class="auto_complete">
               </div>
          </div>
  </body>
</html>
 リスト1のコードは「ajax-autocomplete.htm」ファイルに入っています。CSSセクションは、<div>にWeeFlyと同じような外観を与える働きをします(CSSコードの詳細については本稿では説明しません)。

 <body>セクションはごく簡単です。ここにはラベル、テキストボックス、そして一致したアイテムが入る<div>が含まれます。中心的な関数はbuildAutocompleterで、これはウィンドウのロード時に呼び出されます(Prototypeフレームワークで提供されるEvent.observeメソッドのおかげです)。

 ご覧の通りbuildAutocompleterはAjaxベースのオートコンプリータを作成し、そこにテキストボックス、<div>、およびデータを取得するために呼び出すコンポーネントをアタッチします。Ajax.Autocompleterはサーバーの応答が次の形式になっていることを想定しています。

<ul>
  <li>Item1</li>
  <li>Item2</li>
  ...
</ul>
 つまり、サーバー応答は単純な「HTML順序なしリスト」です。リスト2に、本稿のダウンロードサンプルに収録されている「countries-list.php」のコードを示します。

リスト2 countries-list.php
<?php
     require_once("countries.inc.php");

     if(!isset($_REQUEST["autoCompleteTextField"]))
     {
          die();
     }
     $chars = $_REQUEST["autoCompleteTextField"];
     $listToReturn = array();
     foreach($list as $name)
     {
          if(strtolower($chars) == 
             substr(strtolower($name), 0, strlen($chars)))
          {
               $listToReturn[] = $name;
          }
     }
     if(count($listToReturn) == 0)
     {
          die();
     }
     echo "<ul>";
     foreach($listToReturn as $item)
     {
          echo "<li>" . $item . "</li>";
     }
     echo "</ul>";
?>
 このPHPスクリプトは、ユーザーが入力した文字列を取得し、ユーザーの要求と一致する国名の順序なしリストを組み立てます。なお、この国リストは「countries.inc.php」ファイル内にハードコーディングされています。現実のアプリケーションでは、このリストはデータベース、XMLファイル、またはその他の柔軟なデータストアに格納することになるでしょう。図2に、このPHPスクリプトによって表示される画面の例を示します。

図2 国名リストを表示するAjaxベースのオートコンプリータ。PHPスクリプトcountries.inc.phpの表示例です。
図2 国名リストを表示するAjaxベースのオートコンプリータ。PHPスクリプトcountries.inc.phpの表示例です。
 では、サーバー応答が単純なHTML順序なしリストではなく、XMLやJSONだったらどうなるでしょう。心配はいりません。本稿の終わりまでお読みになれば、Script.aculo.usで提供されるオートコンプリータをベースにして、どんなタイプの応答でも処理可能なオートコンプリータを開発できるようになるはずです。さしあたり、オートコンプリータのカスタマイズ方法を見ていくことにしましょう。

オートコンプリータのカスタマイズ

 既に見たように、Ajax.Autocompleterコンストラクタは4つのパラメータを受け取ります。4番目のパラメータは、オートコンプリータのカスタマイズに使用する任意指定のリテラルオブジェクトです。このオブジェクトのプロパティのうちで最もよく使われるものを表1に示します。

表1 Ajaxベースのオートコンプリータのカスタマイズオプション
オプション説明
paramNameサーバーに送信されるパラメータに使用する名前を表します。デフォルトはテキストボックス名で、ユーザーが入力した文字列がその値となります。
frequencyユーザーが最後の文字を挿入してから要求をサーバーに送信するまでの時間を表します。デフォルトは0.4秒です。
minChars検索を開始するまでの文字数を表します。デフォルトは1です。
parametersサーバーに送信する追加のパラメータのために使用します。これらのパラメータはクエリ文字列形式でなければなりません
(例: param1=value1&param2=value2...)。
indicatorデータ取得時に表示するHTML要素(一般にはデータロードを示すGIF)のIDです。
updateElementユーザーがリストからオプションを選択したときに呼び出すコールバック関数です。デフォルトの関数は選択されたアイテムをテキストボックスに挿入します。
afterUpdateElementupdateElementの呼び出し後に呼び出すコールバック関数です。デフォルトで定義されている関数はありません。
 次のコード例では表1のオプションをいくつか使用しています。このコードで作成するオートコンプリータは、ユーザーが少なくとも2文字を挿入し、最後の文字を入力してから0.5秒が経過したところで要求をサーバーに送信します。

new Ajax.Autocompleter(
     'autoCompleteTextField',
     'autoCompleteMenu',
     'countries-list.php',
     {
          minChars: 2,
          frequency : 0.5,
          indicator : "loadingGif",
          afterUpdateElement : 
            function(){alert($F("autoCompleteTextField"));},
     }
);
 さらに、このコードでは「loadingGif」をIDとするHTML要素を表示し、ユーザーがリストからアイテムを選択すると、そのアイテムを示す警告ボックスを表示します。このコードを、本稿のダウンロードサンプルに収録されている「ajax-autocomplete-options.htm」ファイルと組み合わせて使ってみてください。

 表1のオプションはローカルオートコンプリータでも使用できます(ただし、parametersなど一部のオプションはローカルでは意味を持ちません)。

ローカルオートコンプリータの使用

 Script.aculo.usでは、Ajaxベースのオートコンプリータに加えて、ローカルオートコンプリータも使用できます。ところで、ローカルオートコンプリータとは何でしょうか。基本的に、データがサーバーではなくてローカルなJavaScript配列内に格納されているオートコンプリータのことです。次の例はローカルオートコンプリータの作成方法を示しています。

new Autocompleter.Local(

     'autoCompleteTextField',
     'autoCompleteMenu',
     COUNTRY_LIST,
     {
          minChars: 2
     }
);
 ご覧のように、Ajaxベースのオートコンプリータとよく似ていますが、3番目のパラメータがサーバーサイドコンポーネントのURLではなく、JavaScript配列になっています(本稿のダウンロードサンプルの「local-autocomplete.htm」ファイルに完全な例があります)。ローカルオートコンプリータのカスタマイズに使用できるオプションを表2に示します(表1に示したオプションも使用できます)。

表2 ローカルオートコンプリータのカスタマイズオプション
オプション説明
choicesリスト内に表示するアイテム数の上限を表します。デフォルトは10です。
partialCharspartialSearchに関係するオプションで、何文字入力されたら部分一致を試みるかを示します。
partialSearch部分検索が有効かどうかを示すブール値です。trueの場合は各語の先頭で一致がチェックされます。デフォルトはtrueです。
fullSearch語の先頭および内部で一致をチェックするかどうかを示す値で、trueの場合にこのチェックが行われます。例えば「mil」を検索すると、「Mil」も「Hamilton」も一致することになります。
ignoreCase検索で大文字と小文字を区別するかどうかを示すブール値です。デフォルトはtrueです。

カスタムオートコンプリータの実装

 既に述べたように、Ajaxベースのオートコンプリータの問題点は、サーバー応答として順序なしリスト<ul>を想定していることです。この節では、どんなタイプの応答でも処理できるオートコンプリータの実装方法を具体例で示すことにします。この例では、サーバー応答をリスト更新用のScript.aculo.us関数に渡す前にインターセプトし、オートコンプリータのコンストラクタ呼び出し時にパラメータで定義したコールバック関数へと渡します。

 クライアントコードでこのコールバック関数を実装するわけですが、この関数ではXMLやJSON、あるいはその他の形式の応答を解析し<ul>ブロックを組み立てて、それをScript.aculo.usのupdateChoices関数に渡します(この関数によってリストが更新されます)。このオートコンプリータをAjax.Autocompleter.Customと呼ぶことにします。実装は次のとおりです。

Ajax.Autocompleter.Custom = Class.create(Ajax.Autocompleter, {
  initialize: function(element, update, url, options) {
    this.baseInitialize(element, update, options);
    this.options.asynchronous  = true;
    this.options.onComplete    = this.onComplete.bind(this);
    this.options.defaultParams = this.options.parameters || null;
    this.url                   = url;
    this.options.responseProcessor =
      this.options.responseProcessor || Prototype.K;
  },

  onComplete: function(request) {
       var htmlUL = 
         this.options.responseProcessor(request.responseText, 
         this.element);
     if(htmlUL)
     {
       this.updateChoices(htmlUL);
     }
  }
});
 デフォルトのAjax.Autocompleter実装に関して変更した部分は、responseProcessorという追加的なパラメータの定義とonCompleteの再定義だけです。responseProcessorパラメータは、次の2つのパラメータを受け取るコールバック関数でなければなりません。

  • サーバー応答
  • オートコンプリータが関連付けられる要素(コールバック関数の中でこのパラメータを頻繁に使用することはありません)
 onCompleteを再定義したのは、updateChoicesの呼び出しをインターセプトすることにより、クライアントコードで定義したコールバック関数がサーバー応答を処理して、updateChoicesで期待される適切な文字列を用意できるようにするためです。この新しいオートコンプリータの使用例をリスト3に示します(本稿のダウンロードサンプルに完全なコードが収録されています)。

リスト3 新しいオートコンプリータの使用例
function jsonResponseProcessor(respText, elem)
{
     var countries = eval(respText);
     var ret = "<ul>";
     for(var i = 0; i < countries.length; ++i)
     {
          ret += "<li>" + countries[i] + "</li>";
     }
     ret += "</ul>";
     return ret;
}

function buildAutocompleter()
{
     new Ajax.Autocompleter.Custom(
          'autoCompleteTextField',
          'autoCompleteMenu',
          'countries-list-json.php',
          {
               responseProcessor : jsonResponseProcessor
          }
     );
}
 ご覧のように、カスタムオートコンプリータを使用するのは簡単です。クラスのインスタンスを作成し、パラメータを利用してコールバック関数を渡します。今回の例では、JSON応答形式を処理するjsonResponseProcessorというコールバック関数を使用しています。同じようにしてXML応答を解析するコールバック関数も簡単に実装できます。応答プロセッサをどのように定義するかは開発者の自由です。コールバック関数の出力は<ul>ブロックを表す文字列である必要がありますが、その他の部分は自由に実装してかまいません。

インプレースエディタ

 インプレースエディタとは、基本的には、ユーザーがクリックして編集できるテキストを含んだ<div>のことです。このコントロールに関係する要素は次のとおりです。

  • Ajax.InPlaceEditorクラスのインスタンス
  • 編集されたテキストを受け取って、データベースへの格納や電子メールでの送信などの処理を行うサーバーサイドコンポーネント
 ごく単純なインプレースエディタの作成例をリスト4に示します。

リスト4 ごく単純なインプレースエディタの例
<html>
<head>
<script type="text/javascript" src="../scripts/prototype.js">
  </script>
<script type="text/javascript" src="../scripts/script.aculo.us.js">
  </script>
<script type="text/javascript">
Event.observe(window, "load", function()
     {
          new Ajax.InPlaceEditor('elem', 'editor-test.php',
               {
                    okText: 'Update',
                    cancelText: 'Cancel',
                    size: 70
               }
          );
     }
);
</script>
</head>

<body>
     <div id="elem" style="width: 300px;">
       Click here to make the text editable</div>
</body>

</html>
 サーバーコンポーネントeditor-test.phpは編集されたテキストを受け取り、それを再びクライアントにエコーします。図3はエディタの初期状態を示しており、図4はユーザーがテキストをクリックした後のエディタの状態を示しています。

図3 インプレースエディタの初期状態
図3 インプレースエディタの初期状態
図4 ユーザーがテキストをクリックした後のインプレースエディタの状態
図4 ユーザーがテキストをクリックした後のインプレースエディタの状態
 実際のコードを見れば分かりますが、インプレースエディタの作成はScript.aculo.usを使って簡単に行えます。必要なことは、Ajax.InPlaceEditorのインスタンスを作成し、次の3つのパラメータを渡すことだけです。

  • <div>のID
  • テキストを処理するサーバーコンポーネントのURL
  • エディタをカスタマイズするためのオプションを含んだユビキタスなリテラルオブジェクト
 最もよく使われるインプレースエディタのオプションを表3に示します。

表3 インプレースエディタのカスタマイズオプション
オプション説明
okTextOKボタンに使用するテキストです。
cancelTextCancelリンクに使用するテキストです。
savingText保存アクションの進行中に表示されるテキストです。デフォルトは「Saving..」です。
rowsテキストフィールドに使用する行数です。1より大きい場合は、テキスト領域としてレンダリングされます。デフォルトは1です。
cols使用する列数です。
sizecolsと同じですが、rowsが1のときに適用されます。
onComplete更新が成功した場合に呼び出すコールバック関数です。
onFailure失敗した場合に呼び出すコールバック関数です。

スライダ

 スライダはデスクトップアプリケーションで日常的に使われているコントロールです。例えば、ボリュームコントロールはスライダの典型例です。スライダは基本的に「トラック」と、トラックに沿って動かせる「ハンドル」とから成っています。次の例では、ユーザーがハンドルをドラッグしたときに値を表示する簡単なスライダを作成しています。

Event.observe(window, "load", function()
     {
          new Control.Slider(
               'sliderHandle',
               'sliderTrack',
               {
                    range : $R(0, 100),
                    values :
                       [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
                    onChange : updateValue,
                    onSlide : updateValue
               }
          );
     }
);
 上記のコードはHTMLページの一部にすぎません。実際のHTMLページは本稿のダウンロードサンプルに「simple-slider.htm」という名前で収録されています。

 このコードでは、Control.Sliderのインスタンスを作成し、そこに次のパラメータを渡します。

  • ハンドルを表す<div>のID
  • トラックを表す<div>のID
  • スライダをカスタマイズするためのリテラルオブジェクト
 上の例で使われているオプションは次のとおりです。

  • range -- 値の範囲
  • values -- スライダが取ることのできる値(このオプションを定義すると、スライダに非連続的な値を取らせることができます)
  • onChange -- ユーザーがハンドルの位置を変更したときに呼び出すコールバック関数
  • onSlide -- ユーザーがハンドルをドラッグしたときに呼び出すコールバック関数
 上の例では、onChangeonSlideのどちらについても、コールバック関数としてupdateValueを使用しました。この関数はスライダの現在の値を表示する<div>の状態を更新するだけです。

 このHTMLコードの要件は、次のように、ハンドルがトラックの子要素でなければならないという点だけです。

<div id="sliderTrack">
     <div id="sliderHandle"></div>
</div>
 スライダの動作を図5に示します。

図5 スライダの動作
図5 スライダの動作
 もちろん、CSSコードに手を加えればスライダの外観をさらにカスタマイズすることができます。例えば、スライダの見栄えをよくするために、トラックとハンドルの両方にイメージを使用することができます。

 最後にもう1つヒントを紹介しておきましょう。次のようにすると、スライダの値をプログラム的に変更することができます。

var sliderRef = new Control.Slider(
          'sliderHandle',
          'sliderTrack',
          {
               range: $R(0, 100),
               values : [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
               onChange : upDateValue,
               onSlide : updateValue
          }
     );

// set the slider value
sliderRef.setValue(80);
 この手法を使用するには、まずスライダインスタンスを参照に結びつける必要があります。そうすれば、Control.SliderクラスのsetValueメソッドを使って値を変更できます。

エンドユーザーエクスペリエンスの向上

 これまでアプリケーション開発の世界では、応答性や使用できるコントロールの多彩さといった理由から、Webアプリケーションよりもデスクトップアプリケーションの方が好まれてきました。しかし今日では、Script.aculo.usなどのUIライブラリとAjaxライブラリを利用することで、応答性も見栄えもよいWebアプリケーションを開発できます。

 本稿では、Script.aculo.usのコントロールをWebアプリケーションに組み込んで、より良いエンドユーザーエクスペリエンスを実現するための方法を紹介しました。

著者紹介

Alessandro Lacava(Alessandro Lacava)
イタリアを活動拠点とするソフトウェア開発者、テクニカルライター。Javaと.NETテクノロジ、Webアプリケーション、通信システムを得意分野とする。通信エンジニアリングの資格を保有。連絡先については個人のWebサイトを参照。

関連テーマ
プリンター用
記事を転送
この記事をクリップ!
【特別連載企画】大艦巨砲主義にして卓越したレスポンス--GALAXY S II WiMAX
【特別連載企画】大艦巨砲主義にして卓越したレスポンス--GALAXY S II WiMAX 1月20日より販売が開始されたサムスン製スマートフォン「GALAXY S II WiMAX」。カタログスペックでは、他メーカーのハイエンド機と同じように見えても、実際に使うと卓越したレスポンスに驚かされる。
⇒詳細記事はこちら
⇒連載記事一覧はこちら
注目のトピックス
最新コラム一覧
百式のネットビジネス研究
百式のネットビジネス研究
次のフライトでお好みの座席が空いたら教えてくれる「Expert Flyer」
週刊-サイト別アクセス状況データ
週刊-サイト別アクセス状況データ
12月の主婦層、ベルメゾンが首位を維持(VRI 調査)
アウンのグローバルマーケティング動向
アウンのグローバルマーケティング動向
Web プロモーションにおいて大切なこと―年度末編―
多言語×Web×海外マーケティング情報
多言語×Web×海外マーケティング情報
海外発、注目 AR プロモーション
エンジニア転職ノウハウ開発室
エンジニア転職ノウハウ開発室
楽天が目指す変革──Globalization、Agile、Big Data
中国・台湾ネットビジネス情報最前線
中国・台湾ネットビジネス情報最前線
中国から Web を見てもらいたいならば
マーケティングに活用できる最新トレンド
マーケティングに活用できる最新トレンド
改めて、「導線」最適化に目を向ける
次世代マーケティングチェーンの視点
次世代マーケティングチェーンの視点
ソーシャル時代における BtoC 型 Eコマース成功のポイント
Copyright 2012 internet.com K.K. (Japan) All Rights Reserved.