CodeIgniter и Ajax посредством jQuery

Создаем эффективные и удобные в использовании интерфейсы Web 2.0

Узнайте, как легко можно сделать приложения CodeIgniter более удобными с помощью jQuery. Узнайте, как быстро и эффективно создавать эффективные пользовательские интерфейсы, используя мощь MVC-инфраструктуры CodeIgniter и имеющуюся в jQuery поддержку Ajax (Asynchronous JavaScript and XML).

Ховард Кевин Голдберг, директор по технологиям, imagistic

Kevin Howard GoldbegКевин Ховард Голдберг (Kevin Howard Goldberg) имеет 20-летний опыт работы в индустрии высоких технологий. Он является техническим директором, автором и консультантом, а проживает в Вестлэйк-Вилледж, штат Калифорния. В настоящее время он работает директором по технологиям в Imagistic - технологической и маркетинговой компанией, основанной с его участием в 1997 году. Он является экспертом по Web-разработке и связанным с ней технологиям и входит в наблюдательный совет колледжа компьютерных наук Санта-Моники. Он работал на руководящих должностях в компаниях Film Roman, Lionsgate и Philips Interactive Media. Является автором книги XML: Visual QuickStart Guide (2nd Edition), (PeachPit Press, 2008 г.). С ним можно связаться через страницу http://kehogo.com/contact.



09.12.2011

CodeIgniter – это популярная нетребовательная к ресурсам открытая инфраструктура для разработки Web-приложений, написанная на PHP и основанная на архитектурном шаблоне «модель-представление-контроллер» (Model-View-Controller). jQuery – это быстрая, нетребовательная к ресурсам библиотека JavaScript с открытым кодом, предназначенная для упрощения манипуляций HTML-страницами и Ajax-взаимодействий. При совместном использовании они образуют мощный фундамент для быстрой разработки удобных в использовании Web-сайтов и приложений.

Попробуйте бесплатную версию сервера баз данных DB2 Express 9

Сервер DB2 Express-C можно запустить в работу за считанные минуты, его легко использовать и встраивать, он включает в себя возможности для самоуправления и всю ключевую функциональность DB2 для Linux, UNIX, и Windows, такую как pureXML™. DB2 Express-C предлагает ту же ключевую функциональность, как и другие версии DB2 Express, а также предоставляет надежную основу для создания и развертывания приложений на C/C++, Java™, .NET®, PHP, Ruby on Rails, Python и других языках программирования.

В этой статье рассказывается о том, как интегрировать эти две системы в единую инфраструктуру и как улучшить с помощью jQuery UI существующего Web-приложения. Предполагается, что у вас установлен CodeIgniter версии 1.7.2 или более поздней, MySQL версии 4.1 или более поздней и что вы хорошо умеете работать и с тем и с другим. Помимо этого, нам понадобится библиотека jQuery версии 1.4.2 или более поздней. Если вы только начинаете работать с CodeIgniter или вам нужно освежить свои знания, более подробную информацию об этой инфраструктуре можно найти по ссылкам в разделе Ресурсы.

Web 2.0: Реализуем Ajax с помощью jQuery

Одним из наиболее важных аспектов Web 2.0-приложений является то, что с пользовательской точки зрения они больше напоминают приложение для настольного ПК, а не Web-сайт. А именно, взаимодействие между Web-страницей и Web-сервером не обязательно должно быть видимым, как, например, при отправке данных формы нажатием кнопки Submit, когда нужно подождать, пока Web-сервер обработает отправленную информацию и содержимое всей Web-страницы обновится. Вместо этого обновляется лишь нужное содержимое, тогда как остальная страница остается неизменной.

Взаимодействие без явной отправки данных реализуется с помощью технологии Ajax, которая позволяет Web-разработчикам передавать информацию между Web-клиентом (браузером) и Web-сервером без необходимости обновлять страницу. Более того, такая передача информация может инициироваться без непосредственного участия пользователя.

Когда Web-страница использует Ajax, она асинхронно посылает данные на Web-сервер и получает от него ответы. Эти данные являются обычным текстом и поэтому могут быть представлены в разных форматах, например XML, HTML, JSON, или же быть простым текстом.

Непосредственная передача данных осуществляется с помощью JavaScript и API XMLHttpRequest. Именно здесь на сцене появляется jQuery. Библиотека jQuery намного облегчает процесс использования Ajax. Причем становится легче не только работа с Ajax, но и обновление данных на странице. (Если вы когда-либо пробовали перемещаться по DOM-структуре документа HTML с помощью JavaScript, вы определенно оцените, насколько легче это делать с помощью jQuery!).


Существующее приложение CodeIgniter

Для демонстрации мощи и простоты совместного использования jQuery и CodeIgniter мы в этой статье будем улучшать пользовательский интерфейс существующего Web-приложения. Задача этого приложения - помочь учителю организовывать классные мероприятия и участие в них родителей. Сначала учитель выбирает из одобренного на собрании списка классные мероприятия и планирует для каждого из них дату проведения. Затем родители регистрируются на сайте и вводят контактную информацию своего ребенка (или детей). После этого они могут просматривать список классных мероприятий и выбирать свой уровень участия в них (покупка нужных материалов, помощь в подготовке, присутствие на занятии, его ведение).

Замечание: Эту систему также можно применять в детских спортивных командах, группах YMCA и т.д.

В данной статье в базе данных приложения имеется около 100 мероприятий, 5 родителей и 1 учитель. Родители в системе имеют учетные записи parent1, parent2, . . . parent5. Учетная запись учителя называется teacher, а пароли всех пользователей - ibm.Загрузите Web-приложение и базу данных и настройте их на Web-сервере, чтобы следовать примерам. Для работы приложения необходимо, чтобы инфраструктура CodeIgniter была установлена в корневом каталоге сервера.


Настраиваем jQuery

Для работы с библиотекой jQuery сначала нужно ее загрузить (см. ссылку в разделе Ресурсы).Для каждой версии библиотеки предлагается два файла: несжатый файл и "минимизированный" файл (это сжатая версия, она быстрее загружается, но ее работу невозможно отслеживать и отлаживать). Я рекомендую использовать для разработки полную версию, а в рабочей среде – уменьшенную версию.

Поместите файл библиотеки jQuery в директорию .assets/js в корне вашего Web-сервера. Затем создайте в этой директории новый файл с именем global.js, и добавьте в него код, показанный в листинге 1. Здесь будет храниться код JavaScript всего нашего приложения.

Листинг 1. "Hello World" с использованием jQuery
/* Глобальный JavaScript-файл для работы с библиотекой jQuery  */

// выполняется при загрузке объектной модели документа
 (document object model: DOM) HTML-документа
$(document).ready(function() {

  alert ('Hello World');
	
});

В этой статье,—как и в большинстве приложений—, большая часть кода jQuery будет находиться внутри функции $(document).ready(). Эта функция автоматически выполняется после окончания загрузки DOM-модели HTML-файла.

Чтобы приложение загрузило оба эти файла, отредактируйте файл ./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" />

<!--  две следующие строки загружают библиотеку jQuery и JavaScript-файл -->
<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-сайта. После загрузки страницы будет показано JavaScript-окошко с сообщением "Hello World."


Используем jQuery и Ajax совместно с CodeIgniter

Подготовив библиотеку jQuery и файл global.js можно приступать к улучшению интерфейса приложения. Если вы еще этого не сделали, потратьте несколько минут и войдите в систему как родитель и учитель, чтобы познакомиться с работой системы.

Автоматическая проверка имени пользователя

Мы начнем с улучшения интерфейса страницы регистрации. В настоящее время проверка имени пользователя выполняется при отправке пользователем формы. Однако с помощью Ajax можно выполнять проверку имени на сервере и возвращать результаты еще до отправки формы.

Чтобы сделать это, привяжите следующий код к событию onblur() поля с именем пользователя. Это событие срабатывает, когда курсор покидает это поле. В листинге 3 показан обновленный файл global.js.

Листинг 3. Проверяем, зарегистрировано ли в системе данное имя пользователя
/* Глобальный JavaScript-файл для работы с библиотекой jQuery  */

// выполняется при загрузке объектной модели документа 
(document object model: DOM) HTML-документа
$(document).ready(function() {

  /* ПРОВЕРКА ИМЕНИ ПОЛЬЗОВАТЕЛЯ  */
  // используем элемент с id=username 
  // привязываем нашу функцию к событию onblur этого элемента
  $('#username').blur(function() {

    // получаем значение поля username                           
    var username = $('#username').val();
    
    // Посылаем Ajax-запрос методу "username_taken" контроллера "ajax"
    // отправляем значение поля username
    $.post('/index.php/ajax/username_taken',
      { 'username':username },

      // когда Web-сервер отвечает на запрос
      function(result) {
        // удаляем все сообщения, которые возможно уже показаны
        $('#bad_username').replaceWith('');
        
        // если результат TRUE, выводим на страницу сообщение
        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 отличается от объекта jQuery $(this), который создается из этой переменной. Использование знака $ особенно может запутывать разработчиков на PHP, которые привыкли ставить его перед переменными. Если ваш код работает не так, как вы ожидаете, проверьте правильность использования в нем знака $.

В этом коде на основе DOM-элемента с ID, равным username создается объект jQuery. Далее в нем вызывается метод jQuery blur(), который привязывает функцию к событию onblur() поля username. Эта функция отправляет с помощью Ajax значение поля username методу username_taken контроллера CodeIgniter с именем ajax. Далее она удаляет все существующие сообщения об ошибке и в зависимости от полученного Ajax-ответа отображает или не отображает сообщение об ошибке.

Теперь создадим в директории ./system/application/controllers файл с именем ajax.php для контроллера, который указывается в jQuery-методе.post(). В листинге 4 показан исходный код этого контроллера. (Заметьте, что нет ничего особенного в том, что контроллер называется ajax. Его можно было бы назвать как угодно, главное, чтобы этот контроллер был правильно указан в URL-адресе метода .post().)

Листинг 4. Контроллер CodeIgniter, обрабатывающий Ajax-запросы
<?php

class Ajax extends Controller {

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

  public function username_taken()
  {
    $this->load->model('MUser', '', TRUE);
    $username = trim($_POST['username']);
    // если такое имя пользователя существует, возвращаем 1
    if ($this->MUser->username_exists($username)) {
      echo '1';
    }
  }

}

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

Обратите внимание, что метод username_taken() не возвращает значения. Вместо этого он отправляет клиенту ответ. Ajax-запрос jQuery запрашивает данные Web-страницы и использует полученный результат, он не имеет программного доступа к самому методу.

Итак, наша первая Ajax-функция готова. Перейдите на страницу регистрации и введите уже занятое имя пользователя, чтобы увидеть соответствующее сообщение об ошибке.

Интересно заметить, что у написанного кода jQuery есть побочный эффект. Ajax-функция привязана к полям с ID username, в число которых входит и поле имени пользователя на странице Login. В листинге 5 показано, как изменить объект jQuery, чтобы он был привязан только к полю username, находящемуся внутри формы registration_form.

Листинг 5. Задаем корректное поле username
  /* ПРОВЕРКА ИМЕНИ ПОЛЬЗОВАТЕЛЯ */
  // используем элемент с id=username, находящийся внутри элемента с id=registration_form
  // привязываем нашу функцию к событию onblur этого элемента
  $('#registration_form').find('#username').blur(function() {

Прозрачное обновление и сохранение статуса

Следующее изменение пользовательского интерфейса мы сделаем на странице списка классных мероприятий (Class Activity Listing). Когда родитель хочет обозначить свое участие в каком-либо мероприятии, он устанавливает соответствующий переключатель и затем нажимает кнопку save, чтобы отправить данные со страницы на сервер. Давайте улучшим пользовательский интерфейс, устранив необходимость нажимать ссылку save, а значит, и необходимость отправлять данную страницу на сервер.

Сначала добавим в файл global.js следующий код. Для облегчения описания процесса он разделен между листингами 6, 7 и 8.

Листинг 6. Используем jQuery для получения значений нужных элементов
  /* АВТОМАТИЧЕСКИ СОХРАНЯЕМ ИНФОРМАЦИЮ ОБ УЧАСТИИ  */
  // используем элемент input с атрибутами name=participation_type_id и type=radio
  // привязываем нашу функцию к событию onclick этого элемента
  $('input[name=participation_type_id]:radio').click(function() {
    
    var participation_type_id = this.value;

    // создаем глобальные переменные для последующего использования
    var class_activity_id, user_id;
    
    // получаем два расположенных на форме скрытых элемента ввода 
    // каждый из них является родственником элемента-родителя нажатого переключателя
    // сохраняем их значения в глобальных переменных
    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;
      }
    });

jQuery и DOM-иерархия

Хотя jQuery скрывает большую часть сложностей навигации по DOM-структуре, она не является панацеей. Для эффективного использования jQuery вам все равно нужно иметь базовое понимание иерархических связей элементов документа.

Эта функция привязана к событию onclick() любого переключателя с именем participation_type_id. Она получает значение нажатого переключателя. Затем, используя цепочку методов, она возвращает скрытые элементы формы. Метод map() пропускает каждый элемент через свою функцию, извлекая значения элементов с именами class_activity_id и user_id.

После идентификации значений, указывающих на участие родителя в мероприятии, далее в коде выполняется Ajax-запрос, сохраняющий эту информацию на сервере. Это показано в листинге 7. В ответе на этот запрос сервер не посылает никаких данных, поэтому функция jQuery для обработки ответа пуста (фактически ее можно удалить).

Листинг 7. Отправляем Ajax-запрос к CodeIgniter
    // Ajax запрос к методу "update_user_participation" контроллера "ajax" 
    // отправляем значения полей user_id, class_activity_id и participation_type_id
    $.post('/index.php/ajax/update_user_participation',
      { 'user_id':user_id, 
        'class_activity_id':class_activity_id, 
        'participation_type_id':participation_type_id },
      // когда Web-сервер отвечает на запрос
      function(result) { }
    );

Наконец, давайте поменяем текст, расположенный рядом с переключателями, используя для адресации нужных нам строк имеющийся в jQuery метод next(). Этот код показан в листинге 8.

Листинг 8. Динамически изменяем цвет текста рядом с переключателями
    // задаем красный цвет тексту рядом с нажатым переключателем
    $(this).next().css("color", "red");

    // задаем черный цвет тексту рядом с другими переключателями
    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(), которому мы передаем переменные, отправленные в Ajax-запросе.

Наконец, закомментируем в файле ./system/application/controller/activity.php ссылку save, как показано в листинге 10.

Листинг 10. Удаляем ненужную ссылку save
          '<span style="style="white-space: nowrap;">'.
          $participation_type_buttons.'&nbsp;&nbsp;'.
          /* ссылка save больше не нужна
            '<a href="" onclick="document.forms[\'form_'.$activity->id.'\'].submit();
return false;">save</a>'. */
          '</span>'.
          '</form>';

Теперь изменения информации об участии пользователя в мероприятиях будут автоматически сохраняться без обновления страницы.

Автозавершение полей ввода

Одним из наиболее эффектных и распространенных вариантов применения Ajax является функциональность автозавершения. Войдите в систему как учитель и нажмите Manage Class Activities. Чтобы добавить мероприятие, пользователь должен прокрутить длинный список всех доступных мероприятий. Давайте для улучшения пользовательского интерфейса добавим в файл ./system/application/views/activity_master_listing.php поле ввода с привязанной к нему функцией autosuggest, как показано в листинге 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>

Обратите внимание на два объекта и метода jQuery, привязанных к JavaScript-событию onclick(). Помните, что jQuery является просто библиотекой JavaScript, которая может с легкостью взаимодействовать с JavaScript в любом месте приложения, а не только внутри функции $(document).ready().

Давайте добавим в файл global.js за пределами функции $(document).ready() следующую JavaScript-функцию, привязанную к событию onkeyup() поля ввода class_activity. Ее исходный код показан в листинге 12.

Листинг 12. Реализуем автозавершение с помощью jQuery
/* ПОИСК ВАРИАНТОВ ДЛЯ АВТОМАТИЧЕСКОГО ЗАВЕРШЕНИЯ  */
// срабатывает по событию onkeyup поля ввода
function autosuggest(str){
  // если текст не введен, скрываем div-элемент со списком вариантов
  if (str.length == 0) {
    $('#autosuggest_list').fadeOut(500);
  } else {
    // сначала показываем анимацию загрузки
    $('#class_activity').addClass('loading');
    
    // Ajax-запрос к методу "autosuggest" контроллера "ajax" 
    // отправляем значение параметра str
    $.post('/index.php/ajax/autosuggest',
      { 'str':str },
      function(result) {
        // если есть результат, заносим его в div-элемент со списком вариантов 
        // и показываем его 
        // затем удаляем анимацию загрузки
        if(result) {
          $('#autosuggest_list').html(result);
          $('#autosuggest_list').fadeIn(500);
          $('#class_activity').removeClass('loading');
      }
    });
  }
}

Обратите внимание, что хотя эта функция находится вне функции $(document).ready(), в ней все равно используются объекты и методы jQuery. В ней с помощью метода jQuery .post() вызывается метод autosuggest() контроллера Ajax, который возвращает неупорядоченный список вариантов автозавершения. Код этого метода показан в листинге 13.

Листинг 13. Извлекаем и отправляем результаты автозавершения
  public function autosuggest()
  {
    // экранируем одиночные и двойные кавычки
    $str = addslashes($_POST['str']);
    
    $this->load->model('MActivity', '', TRUE);
    $unscheduled_activities_qry = $this->MActivity->find_unscheduled_activities($str);
    
    // отсылаем список, в котором к событию onclick() каждого элемента li привязана 
    // функция set_activity
    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. Запрашиваем из базы данных незапланированные мероприятия
  // Находим все незапланированные мероприятия, названия которых соответствуют 
  // переданной строке
  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();
  }

Давайте также добавим к элементу 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 показан исходный код обеих функций.

Листинг 16. Получаем и отображаем выбранное мероприятие
/* ЗАДАЕТ МЕРОПРИЯТИЕ, ВЫБРАННОЕ В СПИСКЕ АВТОЗАВЕРШЕНИЯ  */
// срабатывает по событию onclick любого элемента li из списка вариантов автозавершения
// задаем поле class_acitity, ждем и скрываем список вариантов автозавершения
// после чего отображаем информацию о выбранном мероприятии
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);
}

/* ВЫВОДИТ ИНФОРМАЦИЮ О МЕРОПРИЯТИИ, ВЫБРАННОМ В СПИСКЕ АВТОЗАВЕРШЕНИЯ  */
// вызывается в функции set_activity()
// получаем HTML, который нужно отобразить, и отображаем его
function display_activity_details(master_activity_id) {
  
  // Ajax-запрос к методу "get_activity_html" контроллера "ajax" 
  // отправляем значение параметра master_class_activity
  $.post('/index.php/ajax/get_activity_html',
    { 'master_activity_id':master_activity_id },
    // когда Web-сервер отвечает на запрос
    // заменяем innerHTML элемента select_activity
    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);

    // используется код из метода manage_class_listing () 
    // контроллера /controllers/activity.php 
    // генерируем HTML-таблицу на основе результатов запроса 
    $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;
  }

}

Мы позаимствовали этот код из контроллера activity и слегка его изменили: здесь окончательная таблица отсылается клиенту, а не возвращается из метода. В этом коде исполняется SQL-запрос из модели ./system/application/models/mactivity.php, показанный в листинге 18.

Листинг 18. Возвращаем запрошенное мероприятие
  // Возвращает одно мероприятие
  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 показан обновленный SQL-код модели MActivity.

Листинг 19. Возвращаем только незапланированные мероприятия
  // Извлекаем все мероприятия
  function list_class_activities($activity_id)
  {
    // получаем все записи
    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();
    // получаем все записи, за исключением запрошенной
    } 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();
    }
  }

Визуальный календарь для выбора даты

Последнее улучшение пользовательского интерфейса, которое мы сделаем – это замена текстовых полей для ввода даты визуальным календарем. Для этого мы воспользуемся популярным компонентом Datepicker из библиотеки jQuery UI (открытого расширения библиотеки jQuery). Добавьте в файл ./system/application/views/template.php код, показанный в листинге 20.

Листинг 20. Подключаем Datepicker из jQuery UI
<!-- подключаем jQuery UI Datepicker и стили -->
<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  */
  .ui-widget {font-size:1em;}
</style>

Обратите внимание, что вместо загрузки библиотеки мы указываем в теге <script> http://ajax.googleapis.com - URL-адрес репозитория, в котором в свободном доступе хранится множество библиотек, таких как jQuery UI. CSS-файл и изображения были сконфигурированы так, чтобы содержать только необходимые стили (http://jqueryui.com/download). И, наконец, в библиотеке jQuery UI по умолчанию принят размер шрифта 62.5%, поэтому мы соответствующим образом переопределяем это значение.

Компонент Datepicker должен быть привязан к CSS-классу или ID элемента HTML-документа. В файле ./system/application/controllers/activity.php в районе строки 210 в функции редактирования мероприятий назначим класс date-picker для поля ввода даты. Этот код показан в листинге 21.

Листинг 21. Назначаем класс date-picker для редактирования мероприятий
          // добавляем класс date-picker к полю ввода даты
          '<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 для добавления мероприятий
        // добавляем класс date-picker к полю ввода даты
        '<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 показан код, который следует поместить в функцию $(document).ready() в файле global.js.

Listing 23. Binding Datepicker to a class
  /* jQUERY UI CALENDAR PLUGIN */
  // привязываем Datepicker к классу date-picker
  $(".date-picker").datepicker();

Давайте теперь попробуем отредактировать какое-нибудь мероприятие. При помещении курсора в поле ввода даты появляется календарь, позволяющий выбрать дату проведения мероприятия. Однако обратите внимание, что это не работает при добавлении нового мероприятия. Это связано с тем, что HTML-разметка добавления мероприятия записывается уже после загрузки документа (с помощью Ajax), поэтому компонент Datepicker не привязан к этому полю ввода даты. Чтобы исправить это, нужно привязать Datepicker к полю ввода даты после того, как Ajax-функция выведет HTML-код. Это изменение функции display_activity_details() в файле global.js показано в листинге 24.

Листинг 24. Привязываем Datepicker к полю добавления даты
    function(result) { 
      $('#select_activity').html(result);

      // Так как datepicker для добавления мероприятий не загружается вместе с
      // DOM-структурой, мы добавляем его вручную после записи поля ввода даты
      $(".date-picker").datepicker();
    }

Теперь при добавлении мероприятий можно пользоваться календарем Datepicker.


Заключение

Присоединяйтесь к группе Web-разработки в My developerWorks

Обсуждайте различные темы и делитесь ресурсами, связанными с программированием для Web, с другими разработчиками в группе Web-разработки My developerWorks My developerWorks.

Не являетесь членом My developerWorks? Присоединяйтесь прямо сейчас!

Поздравляем с хорошо проделанной работой! Мы узнали, как манипулировать DOM-структурой страницы с помощью объектов jQuery и взаимодействовать с сервером посредством Ajax, что позволило нам значительно улучшить пользовательский интерфейс нашего приложения. Причем во многих случаях мы обошлись написанием лишь небольшого количества кода. Теперь вы можете поработать над дальнейшим расширением приложения, например, реализовать редактирование мероприятий с помощью Ajax непосредственно в интерфейсе или какую-нибудь другую идею, которая пришла к вам в голову при прочтении этой статьи.


Загрузка

ОписаниеИмяРазмер
SQL-файл для создания базы данных classroomclassroom_database.zip15 КБ
Полный исходный код, в том числе файлы CodeIgnitersource_w_codeigniter.zip411 КБ
Исходные файлы MVC для этой статьиsource_only.zip23 КБ
Библиотека jQuery версии 1.4.2jquery_library.zip45 КБ
CSS-файлы для компонента Datepicker из jQuery UIjquery_datepicker.zip53 КБ
Окончательный код, в том числе файлы CodeIgniterfinal_source_w_codeigniter.zip515 КБ
Окончательные файлы MVC для этой статьиfinal_source_only.zip124 КБ

Ресурсы

Научиться

Получить продукты и технологии

  • Загрузите последнюю версию CodeIgniter.
  • Загрузите последнюю версию MySQL.
  • jQuery: загрузите последнюю версию библиотеки jQuery и узнайте о ней больше.
  • jQuery UI: Загрузите дополнительные виджеты с Web-сайта jQuery UI и узнайте больше об этой библиотеке.

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Web-архитектура
ArticleID=780114
ArticleTitle=CodeIgniter и Ajax посредством jQuery
publish-date=12092011