CodeIgniter と Ajax に jQuery を使用する

効果的で使い易い Web 2.0 インターフェースを作成する方法

この記事では、jQuery を使用することで、CodeIgniter アプリケーションの使い易さをいかに簡単に改善できるかを説明します。CodeIgniter の MVC ベースのフレームワーク、そして jQuery による Ajax (Asynchronous JavaScript and XML) を使ったやりとりを利用して、今まで以上に効果的な UI を素早く、効率的に作成する方法を学んでください。

Kevin Howard Goldberg, CTO, imagistic

Kevin Howard Goldbegハイテク産業で 20 年の経験を持つ Kevin Howard Goldberg は、カリフォルニア州ウェストレイク居住の技術責任者、著者、そしてコンサルタントです。現在は、1997年に共同で創設し、賞の栄誉に輝いたデジタル・マーケティング・テクノロジー会社の CTO を務める傍ら、Web 開発および技術のエキスパートとして Santa Monica College Computer Science Advisory Board の委員を務めています。また、Film Roman、Lionsgate、および Philips Interactive Media では管理職に就いていました。著書には、『XML: Visual QuickStart Guide (2nd Edition)』(PeachPit Press、2008年) があります。彼の連絡先は http://kehogo.com/contact です。



2010年 5月 11日

CodeIgniter は、PHP で作成された人気の高い軽量のオープンソース・フレームワークで、MVC (Model-View-Controller) アーキテクチャー・パターンをベースにしています。jQuery は、高速かつ軽量のオープンソース JavaScript ライブラリーであり、HTML ページの操作と Ajax によるやりとりを単純化することを目的として設計されています。この 2 つを組み合わせて使用することで、使い易い Web サイトおよびアプリケーションを迅速に開発するための強力な基盤が実現します。

DB2 Express 9 データベース・サーバーの無料版を試してみてください

わずか数分で起動されるように設計された DB2 Express-C は、使い勝手が良く、システムに組み込むのも簡単です。このデータベース・サーバーには自己管理機能が組み込まれているだけでなく、pureXML™ をはじめ、DB2 for Linux, UNIX, and Windows のコアとなる機能がすべて備わっています。他の DB2 Express エディションと同じ主要なデータ・サーバー基本機能を提供する DB2 Express-C は、C/C++、Java™、.NET®、PHP、Ruby on Rails、Python などの他のプログラミング言語で開発したアプリケーションをビルドおよびデプロイするための堅固な基盤となります。

この記事では、この 2 つのシステムを 1 つのフレームワークに統合する方法、そして jQuery を使用して既存の Web アプリケーションの UI を改善する方法を説明します。記事で前提とするのは、CodeIgniter のバージョン 1.7.2 以降と MySQL のバージョン 4.1 以降が両方ともインストールされていること、そしてこの 2 つを使用する上で十分な実用上の知識を持っていることです。さらに、jQuery ライブラリーのバージョン 1.4.2 以降も必要です。CodeIgniter を初めて使用する場合、またはざっと復習する必要がある場合には、「参考文献」に記載したリンクを利用して詳細を調べてください。

Web 2.0: jQuery を使用した Ajax

最も重要な Web 2.0 の側面の 1 つは、ユーザー・エクスペリエンスが Web サイトよりもデスクトップ・アプリケーションのユーザー・エクスペリエンスに近いことです。具体的に言うと、Web ページとの対話では、ユーザーには Web サーバーとやりとりしていることがわかりません。例えば送信ボタンをクリックした後、送信された情報を Web サーバーが処理し、それによって更新されたコンテンツで Web ページ全体の表示が更新されるのを待つ必要はないということです。Web 2.0 では、変更の必要があるコンテンツだけが更新されて、ページの残りはそのままの状態で維持されます。

この「送信なし」のプロセスは、Ajax を利用して行われます。Web 開発者は Ajax を使うことにより、ページを更新することなく、Web クライアント (ブラウザー) と Web サーバーとの間で情報を送信することができます。その上この情報転送は、直接ユーザーが介入しなくてもトリガーすることが可能です。

Web ページが Ajax を使用すると、そのページは Web サーバーとの間で非同期にデータ送受信を行っている状態となります。送受信されるデータは平文なので、XML や HTML、そして JSON などの異なるフォーマットにすることも、あるいは平文のまま使用することもできます。

実際のデータ送信は、JavaScript と XMLHttpRequest という API を使用して行われます。ここで登場するのが、jQuery です。jQuery ライブラリーは、Ajax を使用するプロセスを極めて単純なものにします。Ajax を容易に使えるようになるだけではありません。jQuery ライブラリーによって、更新されたデータを表示するのも容易になります (JavaScript で HTML DOM をトラバースしようとした経験があるなら、どれほど容易になったか、その違いを実感できるはずです)。


既存の CodeIgniter アプリケーション

CodeIgniter で使用する jQuery の威力と簡単さを実証するため、この記事では既存の Web アプリケーションの UI を改善する具体的な手順を説明します。このアプリケーションは、教師がクラスの行事と、それぞれの行事への保護者の参加を管理できるように設計されたものです。アプリケーションでは教師がまず、委員会が承認した行事のリストのなかからクラスで行う行事を選択し、それぞれの行事の日程を計画します。次に、生徒の保護者がサイトに登録し、その子供に関する連絡先情報を入力します。この情報を入力した後、保護者はクラスの行事リストを表示して、自分の参加レベル (物資の購入、準備手伝い、補佐、または行事のリーダーとしての参加) を選択することができます。

注: このシステムは、子供たちのスポーツ・チームや YMCA グループなどをにも簡単に適用することができます。

この記事のために、アプリケーションのデータベースにはすでに 100 件のイベント、5 人の保護者、そして 1 人の教師がロードされています。保護者には parent1、parent2 というように、parent5 までのユーザー名が設定されています。教師のユーザー名は teacher で、パスワードは全員共通して ibm です。記事の手順に従うには、この Web アプリケーションとデータベースをダウンロードして、Web サーバーにセットアップしてください。このアプリケーションの要件として、CodeIgniter フレームワークはサーバーのルートに置かれている必要があります。


jQuery のセットアップ

jQuery を使用するための最初のステップは、このライブラリーをダウンロードすることです (リンクについては「参考文献」を参照)。バージョン・リリースごとに、圧縮されていないファイルと「縮小」ファイル (この高度に圧縮されたバージョンは短時間でロードできますが、トレースしたいと思っても、それは不可能です) の 2 つが用意されています。開発には圧縮されていないバージョンを使用し、本番には縮小バージョンを使用することをお勧めします。

次に、jQuery ライブラリー・ファイルを Web サーバーのルートにある .assets/js フォルダーに配置します。同じフォルダーに、global.js という名前の新規ファイルを作成してください (リスト 1 を参照)。このファイルが、アプリケーション全体の JavaScript コードを配置する場所となります。

リスト 1. jQuery を使用した「Hello World」
/* Global JavaScript File for working with jQuery library */

// execute when the HTML file's (document object model: DOM) has loaded
$(document).ready(function() {

  alert ('Hello World');
	
});

この記事 (そして大抵のアプリケーション) の jQuery コードの大半は、$(document).ready() 関数のなかに置かれることになります。この関数は、HTML ファイルの DOM ロードが完了した時点でのみ、自動的にトリガーされます。

アプリケーションが jQuery ライブラリー・ファイルと新規に作成したファイルの両方をロードするように、./system/application/views/template.php ファイルをリスト 2 のように編集します。

リスト 2. jQuery およびグローバル JavaScript ファイルのロード
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />

<link href="/assets/css/screen.css" rel="stylesheet" type="text/css" />

<!--  the following two lines load the jQuery library and JavaScript files -->
<script src="/assets/js/jquery-1.4.2.js" type="text/javascript"></script>
<script src="/assets/js/global.js" type="text/javascript"></script>

<title><?php echo $title;?></title>
</head>

ここで、Web サイトの index ページにナビゲートしてみてください。ページがロードされると、「Hello World」という JavaScript アラートが表示されるはずです。


CodeIgniter で使用する jQuery と Ajax

jQuery ライブラリーと global.js ファイルが準備できたところで、ここからはアプリケーションのインターフェースを改善する作業に取り掛かります。まだ実際にこのシステムにログインしていないのであれば、ここで少し時間を割いて保護者として、そして教師としてログインして、このシステムでの行事の操作に慣れてください。

ユーザー名の自動検証

UI を改善する最初の場所は、「Registration (登録)」ページです。現在のところ、ユーザー名が使用済みであるかどうかの検証は、ユーザーがページを送信した後に行われます。けれども Ajax を使用すれば、ページを送信しなくても、サーバー・サイドの検証を実行して結果を返すことができます。

そのためのコードをユーザー名フィールドの onblur() イベントにバインドします。このイベントは、ユーザーのカーソルがフィールドを離れるとトリガーされます。更新後の global.js ファイルは、リスト 3 のとおりです。

リスト 3. ユーザー名が登録済みであるかどうかのチェック
/* Global JavaScript File for working with jQuery library */

// execute when the HTML file's (document object model: DOM) has loaded
$(document).ready(function() {

  /* USERNAME VALIDATION */
  // use element id=username 
  // bind our function to the element's onblur event
  $('#username').blur(function() {

    // get the value from the username field                              
    var username = $('#username').val();
    
    // Ajax request sent to the CodeIgniter controller "ajax" method "username_taken"
    // post the username field's value
    $.post('/index.php/ajax/username_taken',
      { 'username':username },

      // when the Web server responds to the request
      function(result) {
        // clear any message that may have already been written
        $('#bad_username').replaceWith('');
        
        // if the result is TRUE write a message to the page
        if (result) {
          $('#username').after('<div id="bad_username" style="color:red;">' +
            '<p>(That Username is already taken. Please choose another.)</p></div>');
        }
      }
    );
  });  

});

jQuery での $ 記号

jQuery でのドル記号 ($) は、実際には新しい jQuery オブジェクトを作成するために使用されるエイリアスです。したがって、JavaScript 変数の this は、JavaScript 変数から作成される jQuery オブジェクトの $(this) とは異なります。この $ の用法は、変数を $ で始めることに慣れている PHP 開発者にとっては特に混乱しがちです。コードで問題が発生した場合には、$ をどのように使っているかを確認してください。

上記のコードは、ID を username に設定した DOM 要素を使って jQuery オブジェクトを作成した後、jQuery の blur() メソッドを呼び出して、ユーザー名フィールドの onblur() イベントに関数をバインドします。バインドされる関数は Ajax を使用して、ユーザー名フィールドの値を ajax という名前の CodeIgniter コントローラーとそのメソッド、username_taken に POST します。続いて既存のエラー・メッセージをクリアし、Ajax の POST リクエストの結果に応じて、エラー・メッセージを表示するか、表示しないかを決定します。

今度は ./system/application/controllers に、ajax.php という名前のファイルを作成します。これは、jQuery の Ajax .post() メソッドが参照するファイルです。リスト 4 に、このコントローラーのソース・コードを記載します (このコントローラーには ajax という名前を付けてありますが、この名前に特別な理由はありません。.post() メソッド内の URL が適切なコントローラーを参照する限り、どのような名前にでもすることができます)。

リスト 4. Ajax リクエストを処理する CodeIgniter コントローラー
<?php

class Ajax extends Controller {

  public function Ajax() {
  
    parent::Controller(); 
  }

  public function username_taken()
  {
    $this->load->model('MUser', '', TRUE);
    $username = trim($_POST['username']);
    // if the username exists return a 1 indicating true
    if ($this->MUser->username_exists($username)) {
      echo '1';
    }
  }

}

/* End of file ajax.php */
/* Location: ./system/application/controllers/ajax.php */

username_taken() メソッドは値を返す代わりに、そのレスポンスをエコー出力することに注意してください。これは重要な点です。jQuery の Ajax POST リクエストはデータを Web ページに送信し、その結果更新されたページのデータを使用します。つまり、プログラムによってこのメソッド自体に作用することはしません。

これで、最初の Ajax 関数が完成しました。「Registration (登録)」ページにナビゲートし、すでに使われている任意のユーザー名で登録しようとすると、該当するエラー・メッセージが表示されることを確認してください。

興味深いことに、この jQuery コードは、作成時には意図していなかった結果になっています。Ajax 関数がバインドされるのは username という ID を持つフィールドですが、「Login (ログイン)」ページのユーザー名フィールドもこれに該当します。リスト 5 に、registration_form フォーム内のユーザー名フィールドにだけバインドされるように jQuery オブジェクトを変更する方法を示します。

リスト 5. 正しいユーザー名フィールドに制限するためのコード
  /* USERNAME VALIDATION */
  // use element id=username within the element id=registration_form
  // bind our function to the element's onblur event
  $('#registration_form').find('#username').blur(function() {

ステータスのシームレスな更新と保管

次に改善するのは、「Class Activity Listing (クラスの行事リスト)」ページの UI です。保護者が特定の行事に参加することを示すには、その行事に対応するラジオ・ボタンをクリックしてから、保存のためのリンクをクリックしてページを送信するという操作が必要です。この UI を改善し、保存のためのリンクをクリックする操作をなくします。つまり、ページを送信する必要を一切失くすということです。

まずは、以降に記載するコードを global.js ファイルに追加します。プロセスを説明しやすくするために、このコードはリスト 6、リスト 7、リスト 8 に分けてあります。

リスト 6. jQuery による関連要素の値の取得
  /* AUTOSAVE PARTICIPATION */
  // use input element name=participation_type_id and type=radio
  // bind our function to the element's onclick event
  $('input[name=participation_type_id]:radio').click(function() {
    
    var participation_type_id = this.value;

    // create global variables for use below
    var class_activity_id, user_id;
    
    // get the form's two hidden input elements 
    // each is a sibling of the parent of the clicked radio button
    // store their values in the global variables
    var hidden_elements = $(this).parent().siblings('input:hidden');
    $(hidden_elements).map(function() {
      if (this.name == 'class_activity_id') {
        class_activity_id = this.value;
      }
      if (this.name == 'user_id') {
        user_id = this.value;
      }
    });

v

jQuery と DOM 階層

jQuery は DOM をナビゲートする複雑さの大部分を隠してくれますが、万能の解決策というわけではありません。jQuery を効果的に使うには、文書に含まれる要素の階層関係に関する基本的な知識が必要であることに変わりはありません。

この関数がバインドされるのは、participation_type_id というラジオ・ボタンの onclick() イベントです。関数はクリックされたラジオ・ボタンの値を取得した後、一連のメソッドを使用してフォームの隠し要素を返します。map() メソッドはその関数を介して隠し要素のそれぞれを渡し、class_activity_iduser_id の値を取得します。

保護者の参加を設定するために必要な値が認識されると、コードはこの情報を保存するため、Ajax リクエストを実行します (リスト 7 を参照)。このリクエストに対するサーバーのレスポンスはデータをエコー出力しないので、jQuery レスポンス関数は空となります (実際には削除されている可能性もあります)。

リスト 7. CodeIgniter への Ajax リクエストの送信
    // Ajax request to CodeIgniter controller "ajax" method "update_user_participation"
    // post the user_id, class_activity_id and participation_type_id fields' values
    $.post('/index.php/ajax/update_user_participation',
      { 'user_id':user_id, 
        'class_activity_id':class_activity_id, 
        'participation_type_id':participation_type_id },
      // when the Web server responds to the request
      function(result) { }
    );

最後にラジオ・ボタンの横にあるテキストを、各ストリングをターゲットにした jQuery の next() メソッドによって該当する色に変更します。このコードは、リスト 8 のとおりです。

リスト 8. ラジオ・ボタンのテキストの色を動的に変更するコード
    // set the text next to the clicked radio button to red
    $(this).next().css("color", "red");

    // set the text next to the remaining radio buttons to black
    var other_r_buttons = $(this).siblings('input[name=participation_type_id]:radio');
    $(other_r_buttons).map(function() {
      $(this).next().css("color", "black");
    });

  });

jQuery コードは完成したので、今度は ajax コントローラーに update_user_participation() メソッドを作成する必要があります (リスト 9 を参照)。

リスト 9. CodeIgniter でユーザーの参加を処理するコード
  public function update_user_participation()
  {
    $this->load->model('MActivity', '', TRUE);
    $this->MActivity->set_user_participation($_POST);
  }

上記のメソッドは、MActivity モデルの既存の set_user_participation() メソッドを使用します。この set_user_participation() メソッドは、Ajax リクエストが POST した変数を引数に取ります。

最後に、./system/application/controller/activity.php の保存リンクをコメント・アウトします (リスト 10 を参照)。

リスト 10. 不要な保存リンクの削除
          '<span style="style="white-space: nowrap;">'.
          $participation_type_buttons.'&nbsp;&nbsp;'.
          /* the save link is no longer needed
            '<a href="" onclick="document.forms[\'form_'.$activity->id.'\'].submit();
return false;">save</a>'. */
          '</span>'.
          '</form>';

これで、保護者の参加を変更すれば、ページを更新することなく自動的に変更内容が保存されることになります。

オートサジェスト入力フィールド

最も効果的で、最も広く普及している Ajax の機能の 1 つとして挙げられるのは、オートサジェスト、あるいは自動補完とも呼ばれる機能です。教師としてログインして、「Manage Class Activities (クラスの行事の管理)」をクリックしてください。行事を追加するには、選択可能な行事の長々と続くリストをスクロール・ダウンしなければなりません。この UI を改善し、autosuggest 関数にバインドした入力フィールドを ./system/application/views/activity_master_listing.php ファイルの先頭に追加します (リスト 11 を参照)。こうすることで、教師は計画されていないすべての行事のなかから簡単に項目を選択できるようになります。

リスト 11. オートサジェスト入力フィールドの追加
<div id="select_anchor">
  <a href="" onclick="$('#select_anchor').hide(100); 
    $('#select_activity').show(100);
    return false;">
    Select an unscheduled Activity to add >></a>
  <br /><br />
</div>
<div id="select_activity" class="requested_activity" style="display:none;">
  <table>
    <caption>&nbsp;Select an unscheduled Activity</caption>
    <tr class="odd_row_add">
      <td>
        Begin by typing a few letters of an activity name<br />
        then select from the resulting list<br />
        <br />
        <input type="text" value="" id="class_activity" 
          onkeyup="autosuggest(this.value);" class="autosuggest_input" />
        <div class="autosuggest" id="autosuggest_list"></div>
      </td>
    </tr>
  </table>
</div>

JavaScript の onclick() イベントにバインドされた 2 つの jQuery オブジェクトとメソッドに注目してください。jQuery は単なる JavaScript ライブラリーなので、$(document).ready() 関数の中だけでなく、アプリケーション全体にわたって JavaScript とシームレスにやりとりできるという点を覚えておいてください。

次に、global.js ファイルの $(document).ready() 関数の外側に以下の JavaScript 関数を実装します。この関数をバインドするのは、class_activity 入力フィールドの onkeyup() イベントです。リスト 12 に、ソース・コードを記載します。

リスト 12. jQuery によるオートサジェストの実装
/* AUTOSUGGEST SEARCH */
// triggered by input field onkeyup
function autosuggest(str){
  // if there's no text to search, hide the list div
  if (str.length == 0) {
    $('#autosuggest_list').fadeOut(500);
  } else {
    // first show the loading animation
    $('#class_activity').addClass('loading');
    
    // Ajax request to CodeIgniter controller "ajax" method "autosuggest"
    // post the str parameter value
    $.post('/index.php/ajax/autosuggest',
      { 'str':str },
      function(result) {
        // if there is a result, fill the list div, fade it in 
        // then remove the loading animation
        if(result) {
          $('#autosuggest_list').html(result);
          $('#autosuggest_list').fadeIn(500);
          $('#class_activity').removeClass('loading');
      }
    });
  }
}

この関数は $(document).ready() 関数の内部にあるわけではありませんが、それでもやはり、jQuery オブジェクトとメソッドを使用することに変わりありません。この関数の jQuery の .post() メソッドが呼び出している Ajax コントローラーの autosuggest() メソッドは、オートサジェストの結果の順不同リストをエコー出力します。このコードは、リスト 13 のとおりです。

リスト 13. オートサジェストの結果の取得およびエコー出力
  public function autosuggest()
  {
    // escapes single and double quotes
    $str = addslashes($_POST['str']);
    
    $this->load->model('MActivity', '', TRUE);
    $unscheduled_activities_qry = $this->MActivity->find_unscheduled_activities($str);
    
    // echo a list where each li has a set_activity function bound to its onclick() event
    echo '<ul>';
    foreach ($unscheduled_activities_qry->result() as $activity) {
      echo '<li onclick="set_activity(\''.addslashes($activity->name).'\'';
      echo ', '.$activity->id.');">'.$activity->name.'</li>'; 
    }
    echo '</ul>';
  }

次に、データベースからオートサジェストの結果を返す find_unscheduled_activities() メソッドを追加します。リスト 14 に、./system/application/models/mactivity.php から抜粋したコードを記載します。

リスト 14. データベースに対して、計画されていないすべての行事を問い合わせるクエリー
  // Finds all unscheduled activities that match the passed string
  function find_unscheduled_activities($str)
  {
    $this->db->select('id, name
        FROM master_activity 
        WHERE name LIKE \''.$str.'%\'
          AND id NOT IN 
            (SELECT master_activity_id FROM class_activity)
          ORDER BY name', FALSE);
    return $this->db->get();
  }

UI を簡潔にして、リストの要素をクリックできるようにするためには、autosuggest <div> とリストにスタイルを設定する必要もあります。そこで、./assets/css/screen.css にリスト 15 のスタイルを追加します。

リスト 15. オートサジェスト・リストを簡潔にするとともに、クリックできるようにするコード
/***************/
/* Autosuggest */

.autosuggest {
  border:1px solid #000000;
  display:none;
  overflow:hidden;
  padding:0px;
  position:absolute;
  width:200px;
  z-index:1;
}

.autosuggest ul li {
  background-color:#FFFFFF;
  cursor:pointer;
  display:block;
  list-style:none;
  padding:5px;
  white-space:nowrap;
}

.autosuggest ul li:hover {
  background-color:#316AC5;
  color:#FFFFFF;
}

.loading{
  background-image:url('../img/indicator.gif');
  background-position:right;
  background-repeat:no-repeat;
}

.autosuggest_input {
  width:200px;
}

.table_header_add {
  background-color:#FFCC66;
}

.odd_row_add {
  background-color:#FFCC66;
}

これで作業の半分は完了しました。フィールドに文字を入力すると、一致する行事のリストが取得されるようになっています。今度はクラスの行事を選択、表示、保存するためのコードを実装します。まず global.js ファイルに、行事名のフィールドを設定するための関数、そして行事の情報を提供する行を表示するための関数を追加します。リスト 16 に、この 2 つの関数のソース・コードを記載します。

リスト 16. 選択された行事の取得および表示
/* AUTOSUGGEST SET ACTIVITY */
// triggered by an onclick from any of the li's in the autosuggest list
// set the class_acitity field, wait and fade the autosuggest list
// then display the activity details
function set_activity(activity_name, master_activity_id) {
  $('#class_activity').val(activity_name);
  setTimeout("$('#autosuggest_list').fadeOut(500);", 250);
  display_activity_details(master_activity_id);
}

/* AUTOSUGGEST DISPLAY ACTIVITY DETAILS */
// called by set_activity()
// get the HTML to display and display it
function display_activity_details(master_activity_id) {
  
  // Ajax request to CodeIgniter controller "ajax" method "get_activity_html"
  // post the master_class_activity parameter values
  $.post('/index.php/ajax/get_activity_html',
    { 'master_activity_id':master_activity_id },
    // when the Web server responds to the request
    // replace the innerHTML of the select_activity element
    function(result) { 
      $('#select_activity').html(result);
    }
  );
}

このコードもまた、選択された行事を表示する表の行を取得するために Ajax を使用しています。これに対応する HTML は、リスト 17 のコードで生成します。

リスト 17. 行事を表示する HTML 表のエコー出力
  public function get_activity_html()
  {
    $this->load->model('MActivity', '', TRUE);
    $this->load->library('table');

    $requested_activity_id = $_POST['master_activity_id'];
    $requested_activity_qry = 
      $this->MActivity->get_requested_master_activity($requested_activity_id);

    // code leveraged from /controllers/activity.php manage_class_listing() method
    // generate HTML table from query results
    $tmpl = array (
      'table_open' => '<table>',
      'heading_row_start' => '<tr class="table_header_add">',
      'row_start' => '<tr class="odd_row_add">' 
    );
    $this->table->set_template($tmpl); 
    
    $this->table->set_caption('&nbsp;Add this Activity'); 

    $this->table->set_empty("&nbsp;"); 
    
    $this->table->set_heading('<span class="date_column">Date</span>',
                  '<span class="activity_name_column">Activity Name</span>',
                  '<span class="address_column">Address</span>',
                  'City', 'Details');
    
    $table_row = array();

    foreach ($requested_activity_qry->result() as $activity)
    {
      $m_id = $activity->master_activity_id;

      $table_row = NULL;

      $table_row[] = ''.
        '<form action="" name="form_'.$m_id.'" method="post">'.
        '<input type="hidden" name="master_activity_id" value="'.$m_id.'"/> '.
        '<input type="text" name="activity_date" size="12" /> '.
        '<input type="hidden" name="action" value="save" /> '.
        '</form>'.
        '<span class="help-text">format: MM-DD-YYYY</span><br/>'.
        '<a href="" onclick="document.forms[\'form_'.$m_id.'\'].submit();'.
        'return false;">save</a>';


      $table_row[] = '<input type="text" value="'.$activity->name.
        '" id="class_activity" onkeyup="autosuggest(this.value);"'.
        'class="autosuggest_input" />'.
        '<div class="autosuggest" id="autosuggest_list"></div>';
      $table_row[] = htmlspecialchars($activity->address);
      $table_row[] = htmlspecialchars($activity->city);
      $table_row[] = htmlspecialchars($activity->details);

      $this->table->add_row($table_row);
    }    
      
    $requested_activities_table = $this->table->generate();

    echo $requested_activities_table;
  }

}

上記のコードは、行事コントローラーのコードに多少の変更 (最終的な表を返す代わりに、表をエコー出力するなど) を加えただけです。リスト 18 に、./system/application/models/mactivity.php から抜粋した、このコードに必要な SQL クエリーを記載します。

リスト 18. 要求された主な行事を返すためのコード
  // Returns a single master activity record
  public function get_requested_master_activity($id)
  {
    $this->db->select('id as master_activity_id, name, address, city, details');
    $this->db->where('id', $id);
    return $this->db->get('master_activity');
  }

最後に、新しい行事を追加できるだけでなく、計画されていない行事を削除して、リストを昇順で再度ソートできるようにします。リスト 19 に、そのように更新した MActivity モデルの SQL コードを記載します。

リスト 19. 計画されていない行事のみを返すためのコード
  // Retrieve all master activity records
  function list_class_activities($activity_id)
  {
    // get all records
    if (!$activity_id) {
      $this->db->select('ma.id as master_activity_id, ma.name, 
                ma.address, ma.city, 
                ma.details, ca.id as class_activity_id, ca.date
            FROM master_activity ma
            /*LEFT*/ JOIN class_activity ca ON ca.master_activity_id = ma.id
            ORDER BY ca.date /*DESC*/, ma.name', FALSE);
      return $this->db->get();
    // get all records except the one being requested
    } else {
      $this->db->select('ma.id as master_activity_id, ma.name, 
                ma.address, ma.city, 
                ma.details, ca.id as class_activity_id, ca.date
            FROM (SELECT * FROM master_activity 
              WHERE master_activity.id != '.$activity_id.') ma
            /*LEFT*/ JOIN class_activity ca ON ca.master_activity_id = ma.id
            ORDER BY ca.date /*DESC*/, ma.name', FALSE);
      return $this->db->get();
    }
  }

日付を選択するためのビジュアル・カレンダー

最後に行う UI の改善として、日付を入力するためのテキスト入力フィールドをビジュアル・カレンダーに置き換えます。そのために使用するのは、よく使用されている jQuery UI ライブラリー (jQuery ライブラリーのオープソース拡張) のプラグインである、jQuery UI Datepicker です。まずは、./system/application/views/template.php ファイルをリスト 20 のように更新してください。

リスト 20. jQuery UI Datepicker のインクルード
<!-- including the jQuery UI Datepicker and styles -->
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js"
  type="text/javascript"></script>
<link href="/assets/css/jquery-ui-1.7.2.custom.css" rel="stylesheet" type="text/css" />
<style type="text/css">
  /* jQuery UI sizing override */
  .ui-widget {font-size:1em;}
</style>

注意する点として、<script> タグはダウンロードしたライブラリーではなく、jQuery UI をはじめとする多くのライブラリーの無料リポジトリー、http://ajax.googleapis.com を参照しています。また、CSS ファイルとイメージは必要なスタイル (http://jqueryui.com/download) だけが含まれるように構成されています。そして最後の注意点として、jQuery UI ライブラリーは本文のフォント・サイズを 62.5% に設定していることを前提として作成されているので、必要に応じてこのデフォルトのサイズを変更してください。

Datepicker は、HTML 内の CSS クラスまたは ID にバインドされることで動作します。行事を編集する関数の場合には、date-picker という名前のクラスを、./system/application/controllers/activity.php の 210 行目あたりにある日付入力フィールドに割り当てます。このコードをリスト 21 に記載します。

リスト 21. 編集用 date-picker クラスの割り当て
          // add the date-picker class to the date input field
          '<input type="text" name="activity_date" size="12" value="'.
            date('m/d/Y', strtotime($activity->date)).'" class="date-picker" /> '.
          '<input type="hidden" name="action" value="update" /> '.
          '</form>'.
          '<span class="help-text">format: MM/DD/YYYY</span><br/>'.

行事を追加する関数の場合には、同じクラスを、./system/application/controllers/ajax.php の 83 行目あたりにある日付入力フィールドに割り当てます。このコードをリスト 22 に記載します。

リスト 22. 追加用 date-picker クラスの割り当て
        // add the date-picker class to the date input field
        '<input type="text" name="activity_date" size="12" class="date-picker" /> '.
        '<input type="hidden" name="action" value="save" /> '.
        '</form>'.
        '<span class="help-text">format: MM/DD/YYYY</span><br/>'.

最後に Datepicker をバインドして、クラスの行事を編集または追加するときに、このカレンダーが表示されるようにします。リスト 23 に、global.js ファイルの $(document).ready() 関数内部に配置するコードを記載します。

リスト 23. Datepicker とクラスのバインド
  /* jQUERY UI CALENDAR PLUGIN */
  // bind the Datepicker to the date-picker class
  $(".date-picker").datepicker();

早速、クラスの行事を編集してみてください。カーソルを日付入力フィールドに置くとカレンダーが表示され、行事の日付を選択できるようになっているはずです。ただし、行事を追加するときにはカレンダーは表示されません。その理由は、行事を追加するための HTML は (Ajax を使って) 文書がロードされた後に作成されているため、Datepicker がその日付入力フィールドにバインドされていないからです。この問題を修正するには、Ajax 関数が HTML を作成した後に、Datepicker を日付入力フィールドにバインドするようにします。そのために global.js ファイルの display_activity_details() に加えた変更は、リスト 24 のとおりです。

リスト 24. Datepicker と日付追加フィールドのバインド
    function(result) { 
      $('#select_activity').html(result);

      // because the add datepicker is not loaded with the DOM
      // manually add it after the date input field is written
      $(".date-picker").datepicker();
    }

これで、Datepicker カレンダーを使ってクラスの行事を追加できるようになります。


まとめ

My developerWorks の Web Development グループに参加してください

My developerWorks の Web Development グループで、他の開発者と Web 開発について議論し、リソースを共有してください。

まだ My developerWorks のメンバーになっていなければ、今すぐ登録してください!

よく出来ました! jQuery オブジェクトを使用して DOM 操作を組み合わせ、Ajax を使ったシームレスなやりとりを実現することによって、このアプリケーションの UI は大幅に改善されています。しかも多くの場合に、ごくわずかなコードでこのような改善を加えられることがわかった今、このアプリケーションをさらに強化するという課題に取り組んでみるのも一考です。例えば Ajax を使ってクラスの行事をインラインで編集できるようにしたり、あるいはこの記事を読んでいる間に思い付いた他のあらゆる UI を実装したりするなど、さまざまな可能性が考えられます。


ダウンロード

内容ファイル名サイズ
SQL file to create classroom databaseclassroom_database.zip15KB
Full initial code base including CodeIgniter filessource_w_codeigniter.zip411KB
The initial MVC files for this articlesource_only.zip23KB
The jQuery library v1.4.2jquery_library.zip45KB
CSS files needed for jQuery UI Datepickerjquery_datepicker.zip53KB
Full final code base including CodeIgniter filesfinal_source_w_codeigniter.zip515KB
The final MVC files from this articlefinal_source_only.zip124KB

参考文献

学ぶために

製品や技術を入手するために

  • CodeIgniter: CodeIgniter の最新バージョンをダウンロードしてください。
  • MySQL: MySQL の最新バージョンをダウンロードしてください。
  • jQuery: jQuery ライブラリーの詳細を学んで、このライブラリーの最新バージョンをダウンロードしてください。
  • jQuery UI: jQuery UI の Web サイトで、追加ウィジェットの詳細を学んでダウンロードしてください。
  • IBM 製品の評価版: IBM 製品の評価版をダウンロードして、DB2®、Lotus®、Rational®、Tivoli®、および WebSphere® のアプリケーション開発ツールとミドルウェア製品を使ってみてください。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Web development
ArticleID=494506
ArticleTitle=CodeIgniter と Ajax に jQuery を使用する
publish-date=05112010