Управление jqGrid с помощью поля с автозавершением

Владимир | | Ajax, HTML, JavaScript, MySQL, PHP, Web разработка.

Сегодня я продолжу рассказывать о плагине jqGrid и покажу еще один пример его использования.

Если не ошибаюсь, это уже 5-ый пост об этом плагине, поэтому я не буду останавливаться на его установке и настройке. Лучше приведу ссылки на предыдущие части:

1) Query Grid Plugin – «продвинутое» решение для создания таблиц

2) jqGrid: редактирование табличных данных с помощью inline редакторов

3) jqGrid – создание дополнительных кнопок

4) jqGrid – поиск данных

Но для тех, кто их не читал, кратко поясню, о чем вообще речь.

jqGrid – это плагин для библиотеки jQuery, предназначенный для работы с табличными данными. Он поддерживает кучу полезных возможностей вроде разбивки данных на страницы, поиска, добавления, удаления, редактирования записей и т.п.

Естественно, у плагина очень много настроек и вариантов использования, но это не означает, что их хватит на все случаи жизни 😉

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

Как это работает, вы можете посмотреть на демо-страничке

Demo

либо скачать архив с примером и установить его на своем сервере

Source

Реализовать такую систему не сложно.

Потребуются:

1) Библиотека jQuery.

2) Плагин jqGrid.

3) Плагин для создания поля с автозаполением. Я выбрал Ajax AutoComplete for jQuery.

Теперь рассмотрим сам пример.

1) Клиентская часть. Тут нам нужно создать только страничку с таблицей и формой, которая содержит поле с автозаполнением (index.html).

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
  3.  
  4. <head>
  5.   <title>jqGrid + Autocomplete</title>
  6.  
  7.   <meta http-equiv="content-type" content="text/html;charset=utf-8" />
  8.   <meta http-equiv="Content-Style-Type" content="text/css" />
  9.  
  10.   <link rel="stylesheet" type="text/css" media="screen" href="css/reset.css" />
  11.   <link rel="stylesheet" type="text/css" media="screen" href="css/smoothness/jquery-ui-1.7.2.custom.css" />
  12.   <link rel="stylesheet" type="text/css" media="screen" href="css/ui.jqgrid.css" />
  13.   <link rel="stylesheet" type="text/css" media="screen" href="css/styles.css" />
  14. </head>
  15. <body>
  16. <div id="container">
  17.   <h1>jqGrid + Autocomplete</h1>
  18.   
  19.   <table id="list"></table>
  20.   <div id="pager"></div>
  21.   
  22.   <form action="#" method="post" id="autocomplete_form">
  23.     <p>
  24.     <label for="city_field">Название города</label>
  25.     <input type="text" id="city_field" name="city_field" size="20" />
  26.     </p>
  27.   </form>
  28.   ...
  29. </div>
  30. </body>
  31. </html>

* This source code was highlighted with Source Code Highlighter.

* This source code was highlighted with Source Code Highlighter.

2) Подключение и настройка плагинов. Этот код добавляем в конец файла index.html перед закрывающим тегом body.

  1. <script src="js/jquery-1.3.2.min.js" type="text/javascript"></script>
  2. <script src="js/jquery-ui-1.7.2.custom.min.js" type="text/javascript"></script>
  3. <script src="js/i18n/grid.locale-ru.js" type="text/javascript"></script>
  4. <script src="js/jquery.jqGrid.min.js" type="text/javascript"></script>
  5. <script src="js/jquery.autocomplete-min.js" type="text/javascript"></script>
  6. <script type="text/javascript">
  7. $(function() {
  8.   //настройка плагина jqGrid
  9.   jQuery("#list").jqGrid({
  10.    url:'getdata.php',
  11.    datatype: 'json',
  12.    mtype: 'POST',
  13.    colNames:['Город','Страна'],
  14.    colModel :[
  15.     {name:'city', index:'city', width:350},
  16.     {name:'country', index:'country', width:350}
  17.    ],
  18.    pager: '#pager',
  19.    rowNum:10,
  20.    rowList:[10,20,30],
  21.    sortname: 'country',
  22.    sortorder: 'desc',
  23.    viewrecords: true,
  24.    caption: 'Города Украины и России'
  25.   }).navGrid('#pager', {edit:false,add:false,del:false,refresh:true,search:false});
  26.   
  27.   //эта функция добавляет GET параметр в запрос на получение
  28.   //данных для таблицы и обновляет её
  29.   function updateTable(value) {
  30.     jQuery("#list")
  31.       .setGridParam({url:"getdata.php?sel_city="+value, page:1})
  32.       .trigger("reloadGrid");
  33.   }
  34.   
  35.   //настройка плагина Autocomplete
  36.   //при возникновении события onSelect вызываем функцию updateTable
  37.   $('#city_field').autocomplete({
  38.     serviceUrl:'search.php',
  39.     maxHeight:150,
  40.     onSelect: function(value) {
  41.       updateTable(value);
  42.     }
  43.   });
  44.   
  45.   //этот обработчик используется если посетитель ввел название города
  46.   //и нажал Enter
  47.   $('#autocomplete_form').submit(function() {
  48.     updateTable($('#city_field').val());
  49.     return false;
  50.   });
  51. });
  52. </script>

* This source code was highlighted with Source Code Highlighter.

Для демонстрационных целей я использовал урезанную базу данных городов России и Украины, поэтому таблица содержит 2 поля: название города и название страны. На настройках отображения полей и таблицы я останавливаться не буду, т.к. уже об этом рассказывал.

Тут гораздо интереснее другой момент – источники данных.

И для поля, и для таблицы данные приходят в JSON формате, но для таблицы их формирует скрипт getdata.php, а для поля — search.php. Почему используются разные скрипты? Дело в том, что для плагина автозаполнения нужно меньше данных (только название города), чем для таблицы, и их структура отличается, а вводить какие-нибудь специальные параметры в запрос мне показалось не самым лучшим решением.

3) Связываем плагины между собой. Тут нам нужно чтобы при выборе посетителем города из списка произошло обновление данных в таблице.

Для этого мы в обработчик события onSelect (строки 40-42) добавили вызов функции updateTable и передали ей название города.

Теперь нам нужно обновить таблицу, но при этом необходимо как-то указать, что мы хотим получить данные только для выбранного города. Т.к. таблица с данными формируется серверным php скриптом, то нам нужно создать дополнительный параметр и добавить его к запросу.

Для этого с помощью метода setGridParam изменяем параметр url на
getdata.php?sel_city="+value
т.е. мы добавили GET параметр sel_city.
Затем вызываем метод trigger("reloadGrid"), который запускает обновление таблицы.

Еще я добавил вызов функции updateTable в обработчик отправки формы (строки 47-50). На случай если пользователь введет название города и нажмет Enter.

4) Создаем серверные скрипты.

Для автозаполнения (search.php)

  1. <?php
  2. require_once('dbdata.php');
  3.  
  4. try {
  5.   //читаем параметры
  6.   $s_query = $_GET['query'];
  7.   
  8.   //подключаемся к базе
  9.   $dbh = new PDO('mysql:host='.$dbHost.';dbname='.$dbName, $dbUser, $dbPass);
  10.   //указываем, что нужно использовать utf8
  11.   $dbh->exec('SET CHARACTER SET utf8');
  12.  
  13.   $stmt = $dbh->prepare('SELECT city FROM cities WHERE city LIKE :query');
  14.   $search = $s_query.'%';
  15.   $stmt->bindParam(':query', $search);
  16.   $stmt->execute();
  17.   
  18.   $i=0;
  19.   $response->query = $s_query;
  20.   $response->suggestions = array();
  21.   while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
  22.     $response->suggestions[]=$row['city'];
  23.   }
  24.   echo json_encode($response);
  25. }
  26. catch (PDOException $e) {
  27.   echo 'Database error: '.$e->getMessage();
  28. }
  29.  
  30. // end of search.php

* This source code was highlighted with Source Code Highlighter.

Тут, набранные пользователем буквы мы получаем в параметре $_GET['query'].

После этого выполняется один запрос к базе данных (строки 13-16), который находит список всех городов, начинающихся с этих букв.

Затем мы формируем массив с ответом (строки 19-23) и отправляем его браузеру.

Примечание. Структура массива описана в документации к плагину, вам нужно только ее соблюдать.

Скрипт для заплнения таблицы (getdata.php).

  1. <?php
  2. require_once('dbdata.php');
  3.  
  4. try {
  5.   //читаем параметры
  6.   $curPage = $_POST['page'];
  7.   $rowsPerPage = $_POST['rows'];
  8.   $sortingField = $_POST['sidx'];
  9.   $sortingOrder = $_POST['sord'];
  10.   
  11.   $selCity = null;
  12.   if (isset($_GET['sel_city'])) {
  13.     $selCity = $_GET['sel_city'];
  14.   }
  15.   
  16.   //подключаемся к базе
  17.   $dbh = new PDO('mysql:host='.$dbHost.';dbname='.$dbName, $dbUser, $dbPass);
  18.   //указываем, что нужно использовать utf8
  19.   $dbh->exec('SET CHARACTER SET utf8');
  20.  
  21.   //определяем количество записей в таблице
  22.   if (null === $selCity) {
  23.     $rows = $dbh->query('SELECT COUNT(id) AS count FROM cities');
  24.   } else {
  25.     $rows = $dbh->query('SELECT COUNT(id) AS count FROM cities WHERE city='.$dbh->quote($selCity));
  26.   }
  27.   $totalRows = $rows->fetch(PDO::FETCH_ASSOC);
  28.  
  29.   $firstRowIndex = $curPage * $rowsPerPage - $rowsPerPage;
  30.   //получаем список городов из базы
  31.   if (null === $selCity) {
  32.     $res = $dbh->query('SELECT * FROM cities ORDER BY '.$sortingField.' '.$sortingOrder.' LIMIT '.$firstRowIndex.', '.$rowsPerPage);
  33.   } else {
  34.     $res = $dbh->query('SELECT * FROM cities WHERE city='.$dbh->quote($selCity).' ORDER BY '.$sortingField.' '.$sortingOrder.' LIMIT '.$firstRowIndex.', '.$rowsPerPage);
  35.   }
  36.   
  37.   //сохраняем номер текущей страницы, общее количество страниц и общее количество записей
  38.   $response->page = $curPage;
  39.   $response->total = ceil($totalRows['count'] / $rowsPerPage);
  40.   $response->records = $totalRows['count'];
  41.  
  42.   $i=0;
  43.   while($row = $res->fetch(PDO::FETCH_ASSOC)) {
  44.     $response->rows[$i]['id']=$row['id'];
  45.     $response->rows[$i]['cell']=array($row['city'], $row['country']);
  46.     $i++;
  47.   }
  48.   echo json_encode($response);
  49. }
  50. catch (PDOException $e) {
  51.   echo 'Database error: '.$e->getMessage();
  52. }
  53.  
  54. // end of getdata.php

* This source code was highlighted with Source Code Highlighter.

Тут код выглядит немного сложнее, но это только из-за использования пагинации (разбивки на страницы). На самом деле большую его часть я просто скопировал из документации к jqGrid (к тому же, он уже обсуждался).

Обратить внимание нужно на обработку параметра sel_city (строки 12, 22 и 31).

Если этот параметр получен, то в запрос на поиск данных мы добавляем условие WHERE city=…, если нет – берем из базы все города подряд.

Я надеюсь, что у вас не возникнет проблем с этим примером. Идея ведь достаточно простая: добавить параметр с нужными данными к запросу и обработать его в серверном скрипте.

Инструкции по установке и настройке примера есть в архиве.

И, конечно, я буду рад услышать ваше мнение 😉

UPD 21.06.2010 В этом примере обнаружилась недоработка. Оказалось, что IE не хочет передавать название города в UTF-8 (название вставляется в URL, т.е. на сервер приходит в GET параметре). Для решения необходимо перед отправкой закодировать название города с помощью encodeURIComponent (в браузере) и раскодировать с помощью rawurldecode (на сервере).

Интересно почитать

Несколько способов о том как заработать студенту в наше время.

Руководителям: оказание услуг бухучета позволяет сэкономить на штатном бухгалтере