在 CodeIgniter 中使用 jQuery 來達到 Ajax 的功能

參考:http://www.ibm.com/developerworks/web/library/wa-aj-codeigniter/

簡介:本文介紹使用 jQuery 來改善你的 CodeIgniter 應用程式的可用性。藉著利用 CodeIgniter 的 MVC 框架以及透過 jQuery來達到 Asynchronous JavaScript and XML (Ajax) 互動的功能,學習如何快速地建立更有效的 UI。'

CodeIgniter 是一個以 PHP 開發,受歡迎的快速、輕量級、開源的基於 Model-View-Controller (MVC) 架構模式的框架 (framework)。 jQuery 則是一個快速、輕量級、開源的 JavaScript 程式庫,其目的在於簡化 HTML 網頁的操作以及 Ajax 的互動操作。當這兩者結合使用時,將會是快速發展 Web 網站和應用程式的非常有用的工具。

本文展示了如何將這兩個系統結合在一個單一的框架中,以及如何使用 jQuery 來改善現有 Web 應用程式的 UI。在此假設你對 CodeIgniter和SQL已有良好基礎,當然,也可視實際需要再加強相關的技巧,本文的範例已修改成可在版本 2.1.0 的 CodeIgniter 下運作。此外,還需要 jQuery 程式庫,本文的範例可在版本 1.4.2 以上的 jQuery 程式庫運作良好。

Web 2.0: 使用 jQuery 來達到 Ajax 的互動

Web 2.0 的一个重要方面就是用户体验更加类似于桌面应用程序的用户体验。具体来讲,与 Web 页面的互動不需要与 Web 服务器进行 “视觉沟通” — 例如,點击 Submit,等待 Web 服务器处理提交的信息,然后以更新后的内容刷新整個 Web 页面。取而代之的是,只有更新后的内容会被刷新,而页面的其余部分保持不变。

通过使用 Ajax 來实现这种 “submission-less” 的過程,它可以讓 Web 開發人员在不需要刷新页面的情况下在 Web 客戶端(瀏覽器)和 Web伺服器之間传输信息。更棒的是,這種資訊傳遞可以在沒有任何使用者的直接介入下被觸發。

當網頁使用 Ajax 時,與Web伺服器之間可以非同步地傳送和接收資料。這種傳輸的資料是純文字資料,因此,可以在許多不同的格式,如XML,HTML,JSON或只是純文字資料。

实 际的数据传输通过 JavaScript 和称为 XMLHttpRequest 的 API 完成,而这个过程正是 jQuery 发挥作用的地方。jQuery 库极大地简化了使用 Ajax 的过程。并且,不仅简化了 Ajax 的使用,而且还简化了更新数据的显示。如果您曾经尝试著使用 JavaScript 來走訪 HTML 的 DOM,您就能够真正体会到这个过程变得有多么容易!

現有的 CodeIgniter 應用程式

為 了說明在 CodeIgniter 中使用 jQuery 的威力和簡單性,本文将带领你改善一個现有 Web 应用程序的 UI。该应用程序旨在帮助教师管理课堂活动以及每位家长的参与。教师首先从一个经董事会批准的选项列表中选择课堂活动,然后为每个活动安排一个日期。然 后,学生家长登录站点并输入他们的孩子的联系信息。他们可以查看课堂活动列表并选择其参与程度,比如采购、帮助筹备、协助或充当活动的负责人。

此程式及使用的資料庫,已經稍做整理,放在原始範例程式,請各位參考說明自行建立應用程式。雖然資料檔是使用MySQL的語法,但各位可選擇習慣的資料庫系統,自行將語法稍作轉換即可。在所附的資料檔中,包括大約有100多個活動資料,5位家長和1名教師。家長的用戶名是 parent1, parent2, . . . parent5。老師的用戶名是 teacher,所有的密碼都是test。另外,你還要弄個可以執行PHP和CodeIgniter的網頁伺服器,並依範例程式的說明建立應用程式,並經測試之後,才能繼續後面的進度。

設定 jQuery

要開始使用jQuery,首先得下載程式庫,請自行上網搜尋及下載。每個發布的版本都提供兩個檔案:未壓縮的檔案和「縮小的」文件 (這個高度壓縮的版本可更快的載入,但不可能追蹤,如果你想的話)。建議在發展時使用未壓縮的版本,線上使用時則用縮小版。

接下來,將jQuery程式庫檔案放置在Web應用程式的根目錄的 ./assets/js 目錄下。然後,在同一目錄中建立名稱為 global.js 的新檔案,如Listing 1所示。這是你用來放整個應用程式的JavaScript 代碼的檔案。

Listing 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 有兩點要注意的,jQuery 中的 $ 以及 jQuery 與 DOM 架構。

在jQuery中,錢字號 ($) 實際上是用來建立新的jQuery物件的別名。因此,JavaScript 的變數this 是與 jQuery物件 $(this) 不同的,後者是由 JavaScript 變數建立的。對於習慣在變數前加$的PHP開發人員來說,$ 尤其令人感到困惑。如果程式出现问题,那么务必要检查一下 $ 的使用。

尽管 jQuery 隐藏了许多 DOM 导航的复杂性 (the complexity of navigating the DOM),但它也不是万能的。特别是,您還需要了解文档元素之间的层次架构关系,才能更有效地使用 jQuery 。

雖然jQuery隱藏了許多的複雜度,但是應用程式加上Ajax的功能後,除錯上會變得更複雜,可以考使用fixfox加firebug,會事半功倍的。

在這篇文章中,以及大部分的應用程式,jQuery代碼大多會放在 $(document).ready() 的function中。此function只有在HTML文件的DOM載入完成之後才會自動觸發。

要在應用程式載入這兩個檔案,編輯檔案 ./application/views/template.php,如 Listing 2所示。請注意,因為應用程式不一定在Web伺服器的根目錄,所以使用 CodeIgniter 的 base_url() 來指定正確的目錄。並且,設定javascript 的變數 base_url ,以便Ajax的 url 能正確的參照。

Listing 2. 載入 jQuery 和 global.js

<head> <meta http-equiv="content-type" content="text/html; charset=UTF-8" />  <link href="<?=base_url()?>/assets/css/screen.css" rel="stylesheet" type="text/css" />  <!--  the following two lines load the jQuery library and JavaScript files --> <script src="<?=base_url()?>/assets/js/jquery-1.4.2.js" type="text/javascript"></script> <script src="<?=base_url()?>/assets/js/global.js" type="text/javascript"></script> <script type="text/javascript">
     base_url='<?=base_url()?>';
</script> <title><?php echo $title;?></title> </head>

現在,瀏覽到網站的索引頁面。在頁面載入時,JavaScript 的 alert 將顯示「Hello World。」

在 CodeIgniter 中使用 jQuery 和 Ajax

准备好 jQuery 函式庫和 global.js 檔案后,您就可以开始改善您的应用程式的界面了。如果你沒有準備好,花個幾分鐘,以家長和老師的身分登入系統,熟悉一下这些活动如何在系统中運作。

用户名自動驗證

要改善的第一個UI是Registration的頁面。目前,驗證username是否已被使用,是在使用者提交頁面後才進行的。然而,透過Ajax,可以執行伺服器端驗證以及送回結果,而無需提交任何頁面。

要達到此功能,將程式碼綁定到 username欄位的onblur() 事件,此事件會在使用者的遊標離開欄位時觸發。Listing 3 列示了更新後的global.js檔案。

Listing 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>');         }       }     );   });    });

這 段代碼使用ID 為 username 的DOM元素建立了一個jQuery物件。然後,它調用了jQuery的 blur() 方法,后者将一个function绑定到username欄位的 onblur() 事件。此function使用 Ajax 以post的方式将username欄位的值提交到名为 ajax 的 CodeIgniter 的 controller及其方法 username_taken 。接着,清除现有的错误消息,並根据 Ajax post 的结果決定显示或不显示错误消息。

接 下來,在 ./application/controllers 的目錄下,建立一個名為ajax.php的檔案,其會被 jQuery的 Ajax .post() 方法所呼叫。Listing 4顯示了該controller的源代碼。 (注意,對於 controller AJAX的命名沒有什麼特殊規定。它可以任意取名,只要 .post() 方法中的URL 能夠正確的參照到此controller。)

Listing 4. 处理 Ajax 请求的 CodeIgniter controller

<?php  class Ajax extends CI_Controller {    public function __construct()
   {
       parent::__construct();
   }    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: ./application/controllers/ajax.php */

請注意,username_taken() 方法並不是送回一個值,而是列印出它的回應,這一點很重要。 jQuery以Ajax的方式將請求的post資料送到網頁,並使用所產生的頁面資料;它不是以程式呼叫的方式來接觸這個方法本身。

現在,你已完成第一個Ajax function。瀏覽 Registration 頁面,用任何已经被使用的用户名进行注册,已經可以看到相應的錯誤訊息。

不 過,所寫的jQuery代碼會碰到一個意外的結果。 因為此這個 Ajax function被綁定到ID為username的所有欄位,其中包括Login頁面中的username 欄位,所以在登入的時候,也會出現警告的訊息。Listing 5顯示了如何修改jQuery物件,使其只綁定到 registration_form 表單的 username 欄位。

Listing 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() {

無縫狀態更新及儲存

下一個UI的改善是針對Class Activity Listing 的頁面。家長想要參加某個特定的活動,他要點擊相應的 radio 按鈕,然後點擊 save 鏈接以提交頁面。對此UI的改善,就是無需點擊 save 鏈接,因而也無需提交整個頁面。

首先,在 global.js 程式檔中加入下面的程式碼。這些程式碼被分開列示於 Listing 6、Listing 7和Listing 8中,以便更容易地說明此程序。

Listing 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;       }     });

此 function被绑定到任何名为 participation_type_id 的radio按钮的 onclick() 事件。它获得被单击的radio按钮的值。然后,使用一组链接的方法(chained methods )傳回隐藏的表单元素。map()方法通过其 function 传递每个元素,擷取 class_activity_iduser_id 的值。

Having identified the values required to set a parent's participation, the code executes an Ajax request to save this information, as seen in Listing 7. The server's response to this request does not echo any data, so the jQuery response function is empty (and could actually have been removed).

Listing 7. Posting an Ajax request to CodeIgniter

// 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() 方法來鎖定個別的字串,将radio按钮旁边的文字修改为相应的颜色。代码如Listing 8 所示。

Listing 8. 動態改變radio按钮文字的颜色

// 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 的controller中建立 update_user_participation() 方法,如Listing 9 所示。

Listing 9. 在 CodeIgniter 中處理使用者参与活動

public function update_user_participation()   {     $this->load->model('MActivity', '', TRUE);     $this->MActivity->set_user_participation($_POST);   }

此方法使用在 MActivity 模型中已有的 set_user_participation() 方法,它會取用 Ajax 请求以post方式傳送的变數。

最後,將 ./application/views/activity_listing.php 中的save鏈接註解掉,如Listing 10所示。

Listing10. 移除不再使用的save 連結

 '<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>';

你现在可以修改家长的参与狀態,可以不需要刷新页面即可自动保存。

自動提示的輸入欄位

One of the most effective and widespread uses of Ajax is the autosuggest or autocompletion functionality. Log in as a teacher, and click Manage Class Activities. To add an activity, users must scroll down the long list of possible activities. To improve the UI, add an input field bound to an autosuggest function at the top of the ./system/application/views/activity_master_listing.php file, as seen in Listing 11. Doing so allows the teacher to more easily select from all the unscheduled activities.

Listing 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>

Take note of the two jQuery objects and methods bound to the JavaScript onclick() event. Remember that jQuery is simply a JavaScript library and can seamlessly interact with JavaScript throughout an application, not just within the $(document).ready() function.

接 下来,在 global.js 中 $(document).ready() 的 function 的外面的地方,建立下面的 JavaScript 的function。它被綁定至 class_activity 输入欄位的 onkeyup() 事件。源代码如Listing 12 所示。

Listing 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() 的 function中,但是它仍然使用 jQuery 的物件和方法。其中 jQuery的 .post() 方法呼叫 Ajax controller的 autosuggest() 方法,后者传回 autosuggest 结果的未排序的列表。Listing 13 显示了代码。

Listing 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>';   }  

Next, add the find_unscheduled_activities() method to return the autosuggest results from the database. Listing 14 contains the code from ./system/application/models/mactivity.php.

Listing 14. Querying the database for unscheduled activities

  // 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();   } 

You'll also want to style the autosuggest <div> and list so that the UI is clearer and the list elements are clickable. The styles added to ./assets/css/screen.css are shown in Listing 15.

Listing 15. Making the autosuggest list clear and clickable

/***************/ /* 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; }

You're about halfway done. You can type characters into the field to retrieve a set of matching activities. Now, implement the code to select, display, and save an activity for the class. Begin by adding two functions to the global.js file to set the activity name field and display a row with the activity's information. Listing 16 shows the source code for both.

Listing 16. Getting and displaying the selected activity

/* 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);     }   ); }

This code also uses Ajax to get the table row that displays the selected activity. Its HTML is generated by the code in Listing 17.

Listing 17. Echoing the HTML table displaying an activity

  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;   }  } 

This code was leveraged from the activity controller with only a few modifications, including echoing the final table, not returning it. It requires the SQL query shown in Listing 18 from ./system/application/models/mactivity.php.

Listing 18. Returning the requested master activity

  // 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');   } 

Finally, although you can already add a new activity, you want to remove the unscheduled activities and re-sort the list in ascending order. The updated SQL code from the MActivity model is shown in Listing 19.

Listing 19. Only returning unscheduled activities

  // 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();     }   } 

Visual calendar for date selection

The final UI improvement you'll make is to replace the text input fields for entering dates with a visual calendar. To do so, use the jQuery UI Datepicker, which is a popular plug-in from the jQuery UI library (an open source extension of the jQuery library). Update the ./system/application/views/template.php file as shown in Listing 20.

Listing 20. Including the 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>

Notice that instead of having downloaded the library, the <script> tag references http://ajax.googleapis.com, which is a free repository for many libraries, such as the jQuery UI. The CSS file and images were configured to contain only the necessary styles (http://jqueryui.com/download). Finally, the jQuery UI library is built assuming a body font size of 62.5%, so you override its default to size it appropriately.

The Datepicker works by being bound to a CSS class or ID within your HTML. For the edit activity function, assign a class called date-picker to the date input field in ./system/application/controllers/activity.php around line 210. The code is shown in Listing 21.

Listing 21. Assigning the date-picker class for edits

          // 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/>'. 

For the add activity function, assign the same class to the date input field in ./system/application/controllers/ajax.php around line 83, as seen in Listing 22.

Listing 22. Assigning the date-picker class for adds

        // 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/>'. 

Finally, bind the Datepicker so that it shows up when editing or adding a class activity. The code to place inside the $(document).ready() function in the global.js file is shown in Listing 23.

Listing 23. Binding Datepicker to a class

  /* jQUERY UI CALENDAR PLUGIN */   // bind the Datepicker to the date-picker class   $(".date-picker").datepicker(); 

Now try to edit a class activity. When you place your cursor in the date input field, a calendar appears, allowing you to select a date for the activity. However, notice that this doesn't work when trying to add an activity. That's because the add activity HTML is written after the document has already been loaded (using Ajax), so the Datepicker is not bound to its date input field. To fix this, you bind the Datepicker to the date input field after the Ajax function writes the HTML. This change to the display_activity_details() function in the global.js file is shown in Listing 24.

Listing 24. Binding Datepicker to the add date field

    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 日曆來新增班級的活動。

結論

嘉許自己一下,做得很好!你已經學會了透過jQuery物件來結合DOM的操作,並透過Ajax實現無縫通信,顯著地改善此應用程式的UI。在大部分的情況下,實現這些改進的程式碼是相當簡潔的。現在,你可以享受一下挑戰,進一步加強此應用程式,使用內嵌的Ajax來編輯班級活動,或者是去實作你在閱讀這篇文章時所想到的任何其他UI的構想。