Итак в предыдущей статье (jqGrid Часть I:Знакомство) мы с вами подготовили платформу для опытов и выполнили «пробный запуск» плагина, с самыми «базовейшими» параметрами. Согласно которым таблица запрашивает данные с сервера в XML разметке, при этом у нас есть возможность сортировать данные в столбцах.

В данной статье мы продолжим эксперименты и прощупаем еще ряд замечательных возможностей jqGrid, вот план действий:

I. Другие способы загрузки данных
1) Загрузка данных в виде JSON объекта

JSON – как и XML является текстовым форматом обмена данными, при этом намного моложе последнего. Является более прогрессивным методом, благодаря большей гибкости своей архитектуры по сравнению с XML. На тему сравнения XML и JSON есть очень хорошая статья (JSON и XML. Что лучше?). Но при генерировании ответа в JSON методами PHP, есть ряд особенностей при работе с кириллицей. Повествование о которых выходит за рамки данной статьи, поэтому я ограничиваюсь лишь упоминанием.

Итак на практике загрузка таких данных требует следующей конфигурации плагина:

$(function(){
                $('#table').jqGrid({
                              url:'p2e1.php',
                  datatype: 'json',
                             mtype: 'GET',
                             colNames:['Код страны','Код региона', 'Город','Долгота','Широта','nbip'],
                             colModel :[
                                    {name:'country_code', index:'country_code', width:80},
                                    {name:'region_code', index:'region_code', width:80},
                                    {name:'city', index:'city', width:90},
                                    {name:'latitude', index:'latitude', width:60},
                                    {name:'longitude', index:'longitude', width:60},
                                    {name:'nbip', index:'nbip', width:30}],
                            pager: $('#tablePager'),
                            rowNum:10,
                            rowList:[10,20,30,100],
                            sortname: 'city',
                            sortorder: 'asc',
                  caption: 'Загрузка JSON данных',
                  rownumbers: true,
                            rownumWidth: 40
                });
    });

Все изменения я выделил отступами (строки 4, 19-21). Как вы можете видеть в листинге параметру datatype: присвоено значение ‘json’, что говорит плагину о том что от сервера ожидается ответ в виде JSON объекта. Далее я ввел в конфиг таблицы еще три свойства caption, rownumbers, rownumWidth. Что они определяют?

  • caption – если это свойство не пустое, то у таблицы появляется заголовок с текстом, присвоенным этому свойству.
  • rownumbers – если это свойство «истина», то первым столбцом таблицы будет столбец с номерами записей по порядку.
    • rownumWidth – это свойство зависимо от rownumbers. И определяет ширину столбца с нумерацией.

С данного момента, я ввожу еще одно правило в этот цикл статей. Все свойства-параметры инициализации jqGrid вы будете самостоятельно изучать на странице документации плагина в разделе Options и colModel Options. Но при этом я буду комментировать, то на что следует обратить внимание.

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

Пример 1 – используя массив

...
// Начало формирование массива
// для последующего преобразоования
// в JSON объект
$data['page']       = $page;
$data['total']      = $total_pages;
$data['records']    = $count;
// Строки данных для таблицы
$i = 0;
while($row = mysql_fetch_assoc($result)) {
    $data['rows'][$i]['id'] = $row['id'];
    $data['rows'][$i]['cell'][] = $row['country_code'];
    $data['rows'][$i]['cell'][] = $row['region_code'];
    $data['rows'][$i]['cell'][] = $row['city'];
    $data['rows'][$i]['cell'][] = $row['latitude'];
    $data['rows'][$i]['cell'][] = $row['longitude'];
    $data['rows'][$i]['cell'][] = $row['nbip'];
    $i++;
}
// Перед выводом не забывайте выставить header
// с типом контента и кодировкой
header("Content-type: application/json;charset=utf-8");
echo json_encode($data);

Пример 2 – используя объект

...
// Начало формирование объекта
// для последующего преобразоования
// в JSON объект
$data->page       = $page;
$data->total       = $total_pages;
$data->records   = $count;
// Строки данных для таблицы
$i = 0;
while($row = mysql_fetch_assoc($result)) {
    $data->rows[$i]['id'] = $row[id];
    $data->rows[$i]['cell'] = array($row[country_code],$row[region_code],$row[city],$row[latitude],$row[longitude],$row[nbip]);
    $i++;
}
// Перед выводом не забывайте выставить header
// с типом контента и кодировкой
header("Content-type: text/script;charset=utf-8");
echo json_encode($data);

Оба подхода выполняют одни и те же действия, но при этом выбор подхода зависит от ваших предпочтений и уровня мастерства.

Вот ссылка на ДЕМО2.1 и ссылка на архив с примером.
Подытожив, скажу, что как видите в данном способе загрузки данных нет ничего сложного и принцип работы идентичен с загрузкой данных в виде XML, но при этом немного облегчается код серверного скрипта. Также повторюсь, что при кодировании данных в JSON методом PHP следует учитывать особенности работы с кириллицей!

2) Загрузка данных в виде массива

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

$(function(){
$('#table').jqGrid({
  datatype: 'local',
          colNames:['ID','Код страны','Код региона', 'Город','Долгота','Широта','nbip'],
          colModel :[
                        {name:'id', index:'id', width:20},
                        {name:'country_code', index:'country_code', width:80},
                        {name:'region_code', index:'region_code', width:80},
                        {name:'city', index:'city', width:90},
                        {name:'latitude', index:'latitude', width:60},
                        {name:'longitude', index:'longitude', width:60},
                        {name:'nbip', index:'nbip', width:30}
                     ],
          caption: 'Загрузка массива данных'
});
var data = [
            {id: '1', country_code:'AD',  region_code:'02', city:'Canillo', latitude:'42.5667', longitude: '1.6', nbip:'0'},
            {id: '2', country_code:'AD',  region_code:'02', city:'El Tarter', latitude:'42.5833', longitude: '1.65', nbip:'0'},
            {id: '3', country_code:'AD',  region_code:'03', city:'Encamp', latitude:'42.5333', longitude: '1.5833', nbip:'0'},
            {id: '4', country_code:'AD',  region_code:'04', city:'Arinsal', latitude:'42.5667', longitude: '1.4833', nbip:'1'},
            {id: '5', country_code:'AD',  region_code:'04', city:'La Massana', latitude:'42.55', longitude: '1.5167', nbip:'0'},
            {id: '6', country_code:'AD',  region_code:'04', city:'Llorts', latitude:'42.6', longitude: '1.5333', nbip:'0'},
            {id: '7', country_code:'AD',  region_code:'05', city:'Ordino', latitude:'42.55', longitude: '1.5333', nbip:'2'},
            {id: '8', country_code:'AD',  region_code:'06', city:'Sant JuliГ  De LГІria', latitude:'42.4667', longitude: '1.5', nbip:'0'},
            {id: '9', country_code:'AD',  region_code:'07', city:'Andorra La Vella', latitude:'42.5', longitude: '1.5167', nbip:'56'},
            {id: '10', country_code:'AD',  region_code:'08', city:'Engordany', latitude:'42.5167', longitude: '1.55', nbip:'1'},
            {id: '11', country_code:'AD',  region_code:'08', city:'Les Escaldes', latitude:'42.5', longitude: '1.5333', nbip:'0'},
            {id: '12', country_code:'AE',  region_code:'01', city:'Abu Dhabi', latitude:'24.4667', longitude: '54.3667', nbip:'824'},
            {id: '13', country_code:'AE',  region_code:'01', city:'Al Ain', latitude:'24.1917', longitude: '55.7606', nbip:'19'},
            {id: '14', country_code:'AE',  region_code:'03', city:'Deira', latitude:'25.2722', longitude: '55.3111', nbip:'0'},
            {id: '15', country_code:'AE',  region_code:'03', city:'Dubai', latitude:'25.2521', longitude: '55.28', nbip:'7082'},
            {id: '16', country_code:'AE',  region_code:'03', city:'Jumairah', latitude:'25.2097', longitude: '55.2478', nbip:'0'},
            {id: '17', country_code:'AE',  region_code:'04', city:'Fujairah', latitude:'25.1231', longitude: '56.3375', nbip:'1'},
            {id: '18', country_code:'AE',  region_code:'05', city:'Ras Al Khaima', latitude:'25.7911', longitude: '55.9428', nbip:'0'},
            {id: '19', country_code:'AE',  region_code:'05', city:'Ras Al Khaimah', latitude:'25.7911', longitude: '55.9428', nbip:'2'},
            {id: '20', country_code:'AE',  region_code:'06', city:'Dibba', latitude:'25.6167', longitude: '56.2667', nbip:'1'},
            {id: '21', country_code:'AE',  region_code:'06', city:'Sharjah', latitude:'25.3622', longitude: '55.3911', nbip:'297'},
            {id: '22', country_code:'AF',  region_code:'11', city:'Herat', latitude:'34.3469', longitude: '62.1983', nbip:'0'},
            {id: '23', country_code:'AF',  region_code:'13', city:'Kabul', latitude:'34.5167', longitude: '69.1833', nbip:'161'},
            {id: '24', country_code:'AF',  region_code:'23', city:'Iran', latitude:'31.8314', longitude: '65.0689', nbip:'0'},
            {id: '25', country_code:'AF',  region_code:'23', city:'Kandahar', latitude:'31.6125', longitude: '65.7094', nbip:'0'}
           ]
for(var i = 0;i <= data.length; i++){
    $('#table').jqGrid('addRowData',i+1,data[i]);
}
});

Как видите и в этом примере нет ничего «военного», все предельно просто. В качестве datatype: указываем ‘local’. Далее каким-либо образом(в данном примере простым присвоением) создаем массив объектов (каждая строка данных является объектом) и производим добавление данных методом addRowData в цикле (for(var i = 0;i <= data.length; i++)).
На данном этапе мне следует дать небольшой комментарий. Почему я написал «… добавление данных методом …» а при этом вся конструкция выглядит как передача параметра. Т.е. фактически происходит передача названия метода addRowData методу jqGrid() в качестве параметра. Дело все в том, что с версии 3.6 разработчики реализовали новый API для работы с jqGrid, согласно которому запись вида $(‘#table’).jqGrid(‘addRowData’,i+1,data[i]); равноценна $(‘#table’).addRowData(i+1,data[i]); Но будьте внимательны, не все методы могут быть использованы в аннотации нового API, перед использованием методов обязательно ознакомьтесь с документацией по данному методу на странице Methods.

  • addRowData – добавляет в таблицу новую строку данных. При этом строка данных должна выглядеть следующим образом {имя1: значение1, имя2: значение2…}. В качестве первого параметра методу, addRowData передается id вставляемой строки, а вторым объект данных (addRowData(row_id, row_data)).

Также в свойствах инициализации jqGrid вы не найдете параметров панели-листалки, потому что данные уже загружены и нет необходимости запрашивать их порциями.
Если присмотреться, то можно заметить что данный способ загрузки данных напоминает работу с JSON, но только на стороне клиента. Такой способ может пригодиться если вы по каким-либо причинам не можете сформировать XML или JSON ответ с данными от сервера.
3) Конвертирование простой таблицы в jqGrid
Данный способ создания jqGrid будет полезен во время «страховки» на странице. Т.е. у нас есть страница, на которой есть таблица jqGrid в «нормальном браузере», но как же пользователи у которых браузер не поддерживает JavaScript (Простите но тут обязан быть смайл :-D )? Они не увидят таблицу? И вот тут то и пригодится данное свойство плагина.
План действий таков:

  • На сервере выполняется скрипт, который выводит в браузер страницу с таблицей и данными.
  • После загрузки всех элементов страницы выполняется функция преобразования статической таблицы в jqGrid
  • Ну, а если браузер посетителя-бедолаги не поддерживает JS, то он просто увидит таблицу. Которую кстати можно оформить используя стили jQueryUI CSS Framework.

Вот и листинг

<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
<title>Осваиваем jqGrid с Linkexchanger</title></p>
<link rel='stylesheet' type='text/css' media='screen' href='css/flick/jquery-ui-1.7.2.custom.css' />
<link rel='stylesheet' type='text/css' media='screen' href='css/ui.jqgrid.css' />
<p><style>
html, body {
margin: 0;
padding: 0;
font-size: 80%;
}
</style>
<script type='text/javascript' src='js/jquery-1.4.min.js'></script>
<script src='js/i18n/grid.locale-ru.js' type='text/javascript'></script>
<script src='js/jquery.jqgrid.min.js' type='text/javascript'></script>
<script type='text/javascript'>
$(function(){
    $('#table').click(function(){
        tableToGrid('#table');
    });
});
</script></head>
<body>
<?php
// Подключение и выбор БД
//$db = mysql_connect('database_host', 'database_user', 'database_password');
//mysql_select_db('database_name');
// Подключение и выбор БД
$db = mysql_connect('database_host', 'database_user', 'database_password');
mysql_select_db('database_name');</p>
// Запрос выборки данных
$query = 'SELECT id, country_code, region_code, city, latitude, longitude, nbip FROM cities LIMIT 30';
$result = mysql_query($query);
// Строим таблицу с данными
echo "<table id='table' border='1'>";
echo "<thead><tr><th>ID</th><th>Код страны</th><th>Код региона</th><th>Город</th><th>Долгота</th><th>Широта</th><th>nbip</th></tr></thead>";
while($row = mysql_fetch_assoc($result)) {
    echo "<tbody><tr><td>'.$row['id'].'</td><td>'.$row['country_code'].'</td><td>'.$row['region_code'].'</td><td>'.$row['city'].'</td>td>'.$row['latitude'].'</td><td>'.$row['longitude'].'</td><td>'.$row['nbip'].'</td></tr></tbody>";
}
echo "</table>";
?>
</body>
</html>

И ссылка на ДЕМО2.2 (просто кликните на таблицу)
Как видите простейший код, при клике на объект #table собственно таблицу, выполняется функция tableToGrid() которой в качестве параметра передается селектор таблицы которую следует преобразовать в jqGrid.

Использование свойств при конвертировании таблицы в jqGrid
И раз уж мы начали разговор про этот метод инициализации jqGrid, то давайте рассмотрим на примере ДЕМО2.2_1 его работу. А следом и код

var options = {
                    caption: 'Конвертирование таблицы',
                    width: 800,
                    height: 600,
                    colModel :[
                                {name:'ID', width:20},
                                {name:'Код страны', width:80},
                                {name:'Страна', width:100, formatter:'select', editoptions:{value:"AD:Andorra; AE:United Arab Emirates; AF:Afghanistan; AG:Antigua and Barbuda; AI:Anguilla; AL:Albania; AM:Armenia; AN:Netherland Antilles; AO:Angola; AR:Argentina"}},
                                {name:'Код региона', width:80},
                                {name:'Город', width:90},
                                {name:'Долгота', width:60},
                                {name:'Широта', width:60},
                                {name:'nbip', index:'nbip', width:30}
                   ]};
                   tableToGrid("#table",options);

Как видите при использовании этой функции, в качестве второго параметра можно передать объект с параметрами таблицы. Но при этом следует обратить внимание на то, что заголовки столбцов должны иметь такое же имя как и текст в заголовке конвертируемой таблицы. Я думаю вы обратили внимание на дополнительные параметры в строке 8, мы рассмотрим их далее в этой статье.
II. Форматирование данных
1) Форматирование ячеек
Википедия определяет Форматирование как «приведение чего-либо к какому-либо формату». Соответственно в нашем случае это будет преобразование полученных от сервера данных, к другому виду. jqGrid позволяет производить как простое так и сложное форматирование. «Простым форматированием» я условно назвал «Выравнивание» и «Изменением цвета» данных при этом мы «форматируем ячейку».
Давайте посмотрим как это делается на примере ДЕМО2.3

$(function(){
    $('#table').jqGrid({
              datatype: 'local',
              colNames:['ID','Код страны','Код региона', 'Город','Долгота','Широта','nbip'],
              colModel :[
                            {name:'id', index:'id', width:20, align: 'center'},
                            {name:'country_code', index:'country_code', width:80, align: 'right'},
                            {name:'region_code', index:'region_code', width:80, align: 'left'},
                            {name:'city', index:'city', width:90},
                            {name:'latitude', index:'latitude', width:60},
                            {name:'longitude', index:'longitude', width:60},
                            {name:'nbip', index:'nbip', width:30}
                         ],
              caption: 'Простое форматирование',
              width: 600,
              afterInsertRow: function(row_id, row_data){
                                if (row_data.country_code == 'AD') {
                                    $('#table').jqGrid('setCell',row_id,'city','',{'color':'#FF00FF'});
                                }else if(row_data.country_code == 'AE'){
                                    $('#table').jqGrid('setCell',row_id,'city','',{'color':'red'});
                                }else{
                                    $('#table').jqGrid('setCell',row_id,'city','',{'background-color': '#999999'});
                              if(row_data.country_code == 'CZ'){
                                        $('#table').jqGrid('setCell',row_id,'city','',{'color':'#FF00FF', 'font-weight':'bold'},{'title': 'Чехия Ура!'});
                                    }
                                }
                            }
    });
var data = [
            {id: '1', country_code:'AD',  region_code:'02', city:'Canillo', latitude:'42.5667', longitude: '1.6', nbip:'0'},
            {id: '2', country_code:'AD',  region_code:'02', city:'El Tarter', latitude:'42.5833', longitude: '1.65', nbip:'0'},
            {id: '3', country_code:'AD',  region_code:'03', city:'Encamp', latitude:'42.5333', longitude: '1.5833', nbip:'0'},
            {id: '4', country_code:'AD',  region_code:'04', city:'Arinsal', latitude:'42.5667', longitude: '1.4833', nbip:'1'},
            {id: '5', country_code:'AD',  region_code:'04', city:'La Massana', latitude:'42.55', longitude: '1.5167', nbip:'0'},
            {id: '6', country_code:'AD',  region_code:'04', city:'Llorts', latitude:'42.6', longitude: '1.5333', nbip:'0'},
            {id: '7', country_code:'AD',  region_code:'05', city:'Ordino', latitude:'42.55', longitude: '1.5333', nbip:'2'},
            {id: '8', country_code:'AD',  region_code:'06', city:'Sant JuliГ  De LГІria', latitude:'42.4667', longitude: '1.5', nbip:'0'},
            {id: '9', country_code:'AD',  region_code:'07', city:'Andorra La Vella', latitude:'42.5', longitude: '1.5167', nbip:'56'},
            {id: '10', country_code:'AD',  region_code:'08', city:'Engordany', latitude:'42.5167', longitude: '1.55', nbip:'1'},
            {id: '11', country_code:'AD',  region_code:'08', city:'Les Escaldes', latitude:'42.5', longitude: '1.5333', nbip:'0'},
            {id: '12', country_code:'AE',  region_code:'01', city:'Abu Dhabi', latitude:'24.4667', longitude: '54.3667', nbip:'824'},
            {id: '13', country_code:'AE',  region_code:'01', city:'Al Ain', latitude:'24.1917', longitude: '55.7606', nbip:'19'},
            {id: '14', country_code:'AE',  region_code:'03', city:'Deira', latitude:'25.2722', longitude: '55.3111', nbip:'0'},
            {id: '15', country_code:'AE',  region_code:'03', city:'Dubai', latitude:'25.2521', longitude: '55.28', nbip:'7082'},
            {id: '16', country_code:'AE',  region_code:'03', city:'Jumairah', latitude:'25.2097', longitude: '55.2478', nbip:'0'},
            {id: '17', country_code:'AE',  region_code:'04', city:'Fujairah', latitude:'25.1231', longitude: '56.3375', nbip:'1'},
            {id: '18', country_code:'AE',  region_code:'05', city:'Ras Al Khaima', latitude:'25.7911', longitude: '55.9428', nbip:'0'},
            {id: '19', country_code:'AE',  region_code:'05', city:'Ras Al Khaimah', latitude:'25.7911', longitude: '55.9428', nbip:'2'},
            {id: '20', country_code:'AE',  region_code:'06', city:'Dibba', latitude:'25.6167', longitude: '56.2667', nbip:'1'},
            {id: '21', country_code:'AE',  region_code:'06', city:'Sharjah', latitude:'25.3622', longitude: '55.3911', nbip:'297'},
            {id: '22', country_code:'AF',  region_code:'11', city:'Herat', latitude:'34.3469', longitude: '62.1983', nbip:'0'},
            {id: '23', country_code:'AF',  region_code:'13', city:'Kabul', latitude:'34.5167', longitude: '69.1833', nbip:'161'},
            {id: '24', country_code:'AF',  region_code:'23', city:'Iran', latitude:'31.8314', longitude: '65.0689', nbip:'0'},
            {id: '25', country_code:'AF',  region_code:'23', city:'Kandahar', latitude:'31.6125', longitude: '65.7094', nbip:'0'},
            {id: '26', country_code:'CZ',  region_code:'23', city:'Stav', latitude:'50.4667', longitude: '15.4667', nbip:'0'}
           ]
for(var i = 0;i <= data.length; i++){
     $('#table').jqGrid('addRowData',i+1,data[i]);
}
});

Для этого примера я взял код «Загрузки данных из массива». Давайте разберем, то что изменилось. Во-первых для удобства это таблица имеет ширину 600px (width: 600), во-вторых появился обработчик на событие afterInsertRow и в-третьих – в набор данных добавилась строка id 26.
Итак выравнивание текста в ячейке осуществляется простым определением свойства align в модели столбца (colModel).
А вот чтобы раскрасить, а также изменить другие стилевые свойства ячейки, нужно писать пользовательскую функцию, например как та что написал я. Давайте разберемся что же происходит.
Сразу после добавления строки в таблицу возникает событие afterInsertRow (все события вы можете изучить на странице Events), при котором выполняется функция. Функции принимает в качестве параметров (см. описание события) Id строки (row_id) и объект с данными (row_data) текущей строки, вставка которой вызвала событие. Далее смотрим чему равен country_code текущей строки.

  • Если AD то установить ячейке (setCell) в строке row_id с именем city данные » (пусто – не менять текущие данные) и стиль color:#FF00FF. Последнее действие аналогично записи для «обыкновенной» таблицы.
  • Если AE – аналогично, но цвет текста в ячейке сделать red.
  • Иначе всем остальным ячейкам сделать фон #999999 и если попадутся строки с CZ то выделить такие ячейки жирным шрифтом и присвоить атрибуту title текст ‘Чехия Ура!’. Атрибуты ячейки можно выставить передав в качестве 5го параметра функции setCell объект с именами и значениями этих атрибутов.

Как вы понимаете благодаря такому подходу, можно раскрасить таблицу как угодно.
2) Изменение представления данных
Другим мощным инструментом форматирования данных в jqGrid является набор «предопределенных форматтеров» (Predefined Formatter). Это функции, которые выполняются над данными в столбце.
Существует 9 стандартных форматтеров

  • integer – форматирование целых чисел
  • number – форматирование любых чисел
  • currency – форматирование денежных величин
  • date – форматирование даты/времени
  • email – форматирование адресов эл. почты
  • link – форматирование ссылок
  • showlink – генератор ссылок
  • checkbox – форматирование данных имеющих два состояния
  • select - форматирование данных имеющих множество состояний
$(function(){
    $('#table').jqGrid({
      url:'p2e4.php',
      datatype: 'json',
      mtype: 'GET',
      colNames:['id', 'integer', 'number', 'currency','date','email','link','showlink','checkbox','select','ip'],
      colModel :[
        {name:'id', index:'id', width:15},
        {name:'integer', index:'integer', width:50},
        {name:'number', index:'number', width:50},
        {name:'currency', index:'currency', width:60},
        {name:'date', index:'date', width:65},
        {name:'email', index:'email', width:70},
        {name:'link', index:'link', width:300},
        {name:'showlink', index:'showlink', width:130},
        {name:'checkbox', index:'checkbox', width:35},
        {name:'select', index:'select', width:30},
        {name:'ip', index:'ip', width:50}],
      caption: 'Данные в чистом виде',
      autowidth: true
    });
$('#tableFormated').jqGrid({
      url:'p2e4.php',
      datatype: 'json',
      mtype: 'GET',
      colNames:['id', 'integer', 'number', 'currency','date','email','link','showlink','checkbox','select','ip'],
      colModel :[
        {name:'id', index:'id', width:15},
        {name:'integer', index:'integer', width:50, formatter:'integer', formatoptions:{defaultValue: 'n.a.'}},
        {name:'number', index:'number', width:50, formatter:'number',formatoptions:{decimalPlaces: 3}},
        {name:'currency', index:'currency', width:60, formatter:'currency',formatoptions:{prefix: '$', suffix:'p.'}},
        {name:'date', index:'date', width:65, formatter: 'date',formatoptions:{srcformat:'Y-m-d H:i:s',newformat:'F d'}},
        {name:'email', index:'email', width:70, formatter: 'email'},
        {name:'link', index:'link', width:300, formatter:'link',formatoptions:{target: '_blank'}},
        {name:'title', index:'title', width:130, formatter:'showlink',formatoptions:{baseLinkUrl: 'http://www.linkexchanger.su/forum/',showAction: 'viewtopic.php', addParam: '&amp;f=4', idName:'t',target: '_blank'}},
        {name:'checkbox', index:'checkbox', width:35, formatter:'checkbox',formatoptions:{disabled: true}},
        {name:'select', index:'select', width:30, formatter:'select', editoptions:{value:&quot;:Все; black:Черный; white:Белый; yellow:Желтый; red:Красный&quot;}},
        {name:'ip', index:'ip', width:50, formatter:long2ip}],
      caption: 'Встроенное форматирование',
      autowidth: true
    });
function long2ip (proper_address) {
        var output = false;
if ( !isNaN( proper_address ) && ( proper_address >= 0 || proper_address <= 4294967295 ) ) {
            output = Math.floor(proper_address / Math.pow( 256, 3 ) ) + '.' +
                Math.floor( ( proper_address % Math.pow( 256, 3 ) ) / Math.pow( 256, 2 ) ) + '.' +
                Math.floor( ( ( proper_address % Math.pow( 256, 3 ) )  % Math.pow( 256, 2 ) ) / Math.pow( 256, 1 ) ) + '.' +
                Math.floor( ( ( ( proper_address % Math.pow( 256, 3 ) ) % Math.pow( 256, 2 ) ) % Math.pow( 256, 1 ) ) / Math.pow( 256, 0 ) );
        }
return output;
    }
});

Работающий код данного примера можно увидеть на ДЕМО2.4. Или если вы хотите скачать его, то вот ссылка на архив, внутри клиентский и серверный скрипты, а также дамп БД.
Давайте разберемся как все это работает. Сам пример выглядит как две таблицы и как написано в заголовках, верхняя – отображает данные с сервера как они есть, а нижняя – применяет собственные методы форматирования. Как вы уже наверное догадались, в этом примере важен только клиентский код, поэтому серверный скрипт я упростил до минимума, поэтому таблица не сортирует данные в столбцах. Все столбцы кроме последнего названы в соответствии с используемым «форматтером». Все «форматтеры» используются одинаково, указывая имя и параметры в colModel таблицы, описания всех параметров доступны на странице Predefined Formatter документации плагина.
Теперь подробнее по применению в данном примере.

  • formatter:’integer’, formatoptions:{defaultValue: ‘n.a.’} – я переназначил значение по-умолчанию, которое будет отображаться в таблице если сервер не вернул никакого значения (пусто).
  • formatter:’number’,formatoptions:{decimalPlaces: 3} – для данного типа данных я хочу чтобы после запятой было 3 знака.
  • formatter:’currency’,formatoptions:{prefix: ‘$’, suffix:’p.’} – для валют нужно ставить вначале $, а в конце р.
  • formatoptions:{srcformat:’Y-m-d H:i:s’,newformat:’F d’} – для использования этого «форматтера» сначала нужно указать параметру srcformat: маску формата даты в принятом в PHP виде, а затем новый формат newformat:
  • formatter: ‘email’ – этот «форматтер» не имеет параметров, он всего лишь добавляет mailto: к адресам эл.почты
  • formatter:’link’,formatoptions:{target: ‘_blank’} – с помощью ‘link’ можно указать target открытия ссылки
  • formatter:’showlink’,formatoptions:{baseLinkUrl: ‘http://www.linkexchanger.su/forum/’, showAction: ‘viewtopic.php’, addParam: ‘&f=4′, idName:’t', target: ‘_blank’} - а вот с помощью этого «форматтера» можно генерировать ссылки. В нашем примере сервер возвращает название раздела форума linkexchanger в поле showlink в верхней таблице, при этом в нижней таблице вы видите уже готовую ссылку на тему. Это делается указанием следующих параметров:
    • baseLinkUrl: – базовая (не изменяющаяся) часть адреса.
    • showAction: – имя скрипта или метода сервера, в нашем примере это скрипт, который показывает тему.
    • addParam: – дополнительные параметры адреса, в нашем случае это идентификатор ветки форума.
    • idName: – какой параметр использовать в качестве имени идентификатора записи, в нашем случае темы форума. А вот сам идентификатор записи (темы на форуме) равен id строки в таблице.
  • formatter:’checkbox’,formatoptions:{disabled: true} – удобно использовать при отображении булевых данных (данных которые имеют только два значения), намного нагляднее видеть «флажок» вместо 0 или 1 например. При этом «флажок» можно сделать активным (formatoptions:{disabled: false}) и использовать при быстром редактировании (об этом в последующих статьях).
  • formatter:’select’, editoptions:{value:»:Все; black:Черный; white:Белый; yellow:Желтый; red:Красный»} – этот «форматтер» очень пригодится при отображении данных, имеющих много значений, но при этом все значения известны. В нашем примере замена названий цветов.

На этом Стандартные «форматтеры» закончились, а в последнем столбце используется пользовательский. Он представляет из себя функцию function long2ip (proper_address) полный аналог PHP’шной функции, но написанной на и для JS, которая переводит IP из unsignet int в «человеко-понятный» вид октетов с точками.
Если возникла необходимость создать сложный пользовательский «форматтер» со множеством параметров, то на странице Predefined Formatter можно посмотреть пример расширения jqGrid своим «форматтером».
III. Панели инструментов и дополнительные панели
1) Панель-листалка (Pager)
C этой панелью мы уже знакомы, именно ее мы инициализировали устанавливая свойства pager:, rowNum:, rowList: в предыдущих примерах. В принципе об этой панели рассказывать более нечего, я лишь приведу ссылку на прочие свойства панели Pager, которые возможно понадобятся вам для решения какой-то специфической задачи.
2) Панель инструментов (Navigator)
Данная панель совсем не является панелью это функция, которая позволяет добавлять элементы управления (кнопки) на панель-листалку. Т.е. если вы хотите использовать pager, то вы обязательно должны его объявить при инициализации jqGrid хотя бы со стандартными параметрами, без использования rowNum:, rowList:. После этого уже можно добавлять кнопки, давайте взглянем на ДЕМО2.5. Добавление кнопок стандартных функций.

$(function(){
        var pager = $('#tablePager');
$('#table').jqGrid({
                  url:'p2e1.php',
                  datatype: 'json',
                  mtype: 'GET',
                  colNames:['Код страны','Код региона', 'Город','Долгота','Широта','nbip'],
                  colModel :[
                    {name:'country_code', index:'country_code', width:80},
                    {name:'region_code', index:'region_code', width:80},
                    {name:'city', index:'city', width:90},
                    {name:'latitude', index:'latitude', width:60},
                    {name:'longitude', index:'longitude', width:60},
                    {name:'nbip', index:'nbip', width:30}],
                  pager: pager,
                  sortname: 'city',
                  sortorder: 'asc',
                  caption: 'Pager в качестве панели инструментов',
                  autowidth: true
         }).jqGrid('navGrid', pager);
});

Итак друзья мы с вами переступили порог начального уровня использования плагина, с этого момента я буду рассказывать о продвинутых функциях jqGrid.
Как вы уже заметили на листалке появились 6 кнопок, при этом 4 «практически не работают», 1 – «практически работает» и 1 работает, давайте разберемся. Листинг выглядит вполне «стандартно», разве что строка var pager = $(‘#tablePager’); может вызвать легкое недоумение у новичков, но это обычная практика программирования JS, а именно кэширование, об этом написан цикл хороших статей, возьмите эту методику на вооружение! Далее вы можете видеть что после инициализации jqGrid я инициализирую панель Navigator используя метод navGrid. Данному методу в качестве первого параметра передается селектор панели листалки, вторым параметром (не указан в листинге) – объект в котором указывается функции (редактировать, добавить и т.п.) которые необходимо задействовать на панели (например {view:true, del:false}), а далее идут объекты с параметрами по каждой из функций в определенном порядке. Давайте я приведу иллюстрацию в виде списка:

  • pagerSelector
  • {refresh: true(false), add: true(false), del: true(false), edit: true(false), search: true(false), view: true(false)}
  • {… параметры редактирования …}
  • {… параметры добавления …}
  • {… параметры удаления …}
  • {… параметры поиска …}
  • {… параметры просмотра …}

Я уверен, что теперь вам стало ясно почему не работают или не совсем работают задействованные функции, потому что они просто не настроены. Т.к. использование этих функций будет рассмотрена в последующих статьях, я не буду продолжать рассмотрение настроек, а перейду к следующему подпункту Добавление пользовательских кнопок.
jqGrid позволяет добавлять на панель pager пользовательские кнопки и назначать на них функции, ниже приведен листинг ДЕМО2.6

$(function(){
var pager = $('#tablePager');
$('#table').jqGrid({
              url:'p2e1.php',
              datatype: 'json',
              mtype: 'GET',
              colNames:['Код страны','Код региона', 'Город','Долгота','Широта','nbip'],
              colModel :[
                {name:'country_code', index:'country_code', width:80},
                {name:'region_code', index:'region_code', width:80},
                {name:'city', index:'city', width:90},
                {name:'latitude', index:'latitude', width:60},
                {name:'longitude', index:'longitude', width:60},
                {name:'nbip', index:'nbip', width:30}],
              pager: pager,
              sortname: 'city',
              sortorder: 'asc',
              caption: 'Pager в качестве панели инструментов',
              autowidth: true
     }).jqGrid('navGrid', pager,{add: false, del: false, edit: false, search: false});
$('#table').jqGrid('navSeparatorAdd','#tablePager');
     $('#table').jqGrid('navButtonAdd','#tablePager',{
                                              caption: 'Закрутить ',
                                              title: 'Ключ рожковый, обыкновенный',
                                              buttonicon: 'ui-icon-wrench',
                                              onClickButton: function(){
                                                                 alert('Скрип, скрип, скрип!..');
                                                             },
                                              position:'last'
               }).jqGrid('navButtonAdd','#tablePager',{
                                              caption: 'Замкнуть ',
                                              title: 'Открытый замок',
                                              buttonicon: 'ui-icon-unlocked',
                                              onClickButton: lock,
                                              position:'last'
});
function lock(){
                  alert('Взяли и замкнули что-то...');
              }
});

В данном примере после стандартных кнопок, из которых я оставил только «Обновить», вставлен разделитель (separator) и две кнопки «Закрутить» и «Замкнуть», простите но оригинальнее я не смог ничего придумать. По нажанию на эту кнопку вызываются функции, которые показывают стандартный alert.
Разделитель добавляется методом navSeparatorAdd, первым параметром которого является строка-селектор панели-листалки (pager), а в качестве второго (не указан в листинге) объект с параметрами разделителя.

Вот тут следует немного отвлечся и обратить ваше внимание на небольшой ньюанс, возможно разработчики что-то не доделали или не захотели доделать, но при использовании методов navSeparatorAdd и navButtonAdd в качестве первого параметра должна быть передана именно строка-селектор, но никак не переменная содержащая последний.

Параметры разделителя по-умолчанию:
{sepclass: ‘ui-separator’, sepcontent: »}
Где

  • sepclass: – класс в CSS ui.jqgrid.css, который определяет стиль разделителя. Можно использовать если захотите изменить внешний вид разделителя.
  • sepcontent: – контент, который может быть помещен в разделитель.

Кнопка вставляется с помощью метода navButtonAdd
{ caption:’NewButton’, buttonicon:’ui-icon-newwin’, onClickButton:null, position: ‘last’, title:’ ‘, cursor: ‘pointer’}
Где

  • caption: – надпись на кнопке
  • title: – атрибут кнопки, используется как подсказка
  • buttonicon: – название класса иконки из jQuery UI CSS Framework
  • onClickButton: – функция, которая будет выполнена при клике на кнопке
  • position: (‘first’ или ‘last’) – добавить кнопку до или после стандартных кнопок
  • cursor: – CSS свойство, определяющее вид курсора при наведении на элемент
  • id: – с помощью этого свойства можно задать значение атрибуту id контейнеру(TD – обыкновенная ячейка таблицы) в котором находится кнопка.

Однако при всем своем удобстве, у данного подхода к созданию панели инструментов есть ряд недостатков, таких как то что панель находится в нижней части таблицы, мало места для каких-то дополнительных элементов, большого размера и т.п. Для этих целей разработчики добавили еще и возможность создания пользовательских панелей.
3) Пользовательские панели
Вот ДЕМО2.7 листинги которого приведены ниже.
Клиентская часть

$(function(){
       $('#table').jqGrid({
           sortable: true,
                  url:'p2e1.php?userdata=true',
                  datatype: 'json',
                  mtype: 'GET',
                  colNames:['Код страны','Код региона', 'Город','Долгота','Широта','nbip'],
                  colModel :[
                    {name:'country_code', index:'country_code', width:80},
                    {name:'region_code', index:'region_code', width:80},
                    {name:'city', index:'city', width:90},
                    {name:'latitude', index:'latitude', width:60},
                    {name:'longitude', index:'longitude', width:60, resizable: false},
                    {name:'nbip', index:'nbip', width:30}],
                  pager: $('#tablePager'),
          toolbar: [true,'both'],
                  sortname: 'city',
                  sortorder: 'asc',
                  caption: 'Пользовательские панели инструментов',
                  autowidth: true,
                  loadComplete: function() {
                                    var udata = $('#table').jqGrid('getUserData');
                                    $('#tb_table').css('text-align','right').html(udata.msg+' '+udata.sum_regions_numbers+' '+udata.button);
                                }
    });
$("#t_table").height(60); //Set height of toolbar
    $("#t_table").append('<input id="say_hello" type="button" value="Привет" style="height:60px; width:80px">');
    $("#say_hello").click(function(){
            alert("Привет! Спасибо что читаете linkexchanger.su!");
    });
    $('#show_sum').live('click',function(){
        var val = $(this).val();
        alert('Обратите внимание, с сервера мы получили кнопку с сууммой '+val+', а обработчик назначили уже на странице');
    });
   });

И серверная, практически полностью повторяющая пример 2.1

// Начало формирование массива
// для последующего преобразоования
// в JSON объект
$data['page']       = $page;
$data['total']      = $total_pages;
$data['records']    = $count;
// Дополнительная информация с сервера
if($_GET['userdata']){
  $data['userdata']['msg'] = '<span style="font-weight: normal; color: red;">Сумма всех чисел в столбце <em>"region_code"<em> равна</span> ';
  $data['userdata']['sum_regions_numbers'] = '<em>'. $row['sum'].'<em>';
  $data['userdata']['button'] = '<input id="show_sum" type="button" value="'.$row['sum'].'">';
}
// Строки данных для таблицы
$i = 0;
while($row = mysql_fetch_assoc($result)) {
    $data['rows'][$i]['id'] = $row['id'];
    $data['rows'][$i]['cell'][] = $row['country_code'];
    $data['rows'][$i]['cell'][] = $row['region_code'];
    $data['rows'][$i]['cell'][] = $row['city'];
    $data['rows'][$i]['cell'][] = $row['latitude'];
    $data['rows'][$i]['cell'][] = $row['longitude'];
    $data['rows'][$i]['cell'][] = $row['nbip'];
    $i++;
}
// Перед выводом не забывайте выставить header
// с типом контента и кодировкой
header("Content-type: text/script;charset=utf-8");
echo json_encode($data);

Ну а теперь по традиции давайте разберем пример подробнее
jqGrig позволяет создавать две независимые панели инструментов. Для этого стоит свойству toolbar: присвоить массив [true,'both'], элементы которго в данном случае означают, что нужно создать обе(верхнюю и нижнюю) панели инструментов. Вместо ‘both’ также можно указать ‘top’ или ‘bottom’ для верхней и нижней панелей соответственно.
Теперь давайте рассмотрим первый вариант манипуляции с элементами на панелях, начнем с верхней панели. При инициализации плагина с определенным свойством toolbar: jqGrid автоматически выставит атрибут id верхней панели как id=»t_»(«t_table» в нашем случае), а нижнюю id=»tb_» («tb_table» в нашем случае). С помощью этих идентификаторов можно отыскать «тулбары» в DOM и выполнить например такие манипуляции

$("#t_table").height(60);
$("#t_table").append('<input id="say_hello" type="button" value="Привет" style="height:60px; width:80px">');
...
$("#say_hello").click(function(){
            alert("Привет! Спасибо что читаете linkexchanger.su!");
});

Первая строка сделает высоту верхней панели равной 60px, а вторая поместит на нее кнопку, код которой вы видите. После этого определяется функция-обработчик которая выполнится при щелчке по добавленной кнопке. Думаю такая методика использования не вызовет затруднений.
А вот второй, альтернативный вариант манипуляций с элементами на панелях, иллюстрируется на примере нижней панели. Это следующие строки кода

...
loadComplete: function() {
                                    var udata = $('#table').jqGrid('getUserData');
                                    $('#tb_table').css('text-align','right').html(udata.msg+' '+udata.sum_regions_numbers+' '+udata.button);
                                }
...
 $('#show_sum').live('click',function(){
        var val = $(this).val();
        alert('Обратите внимание, с сервера мы получили кнопку с суммой '+val+', а обработчик назначили уже на странице');
    });
...

Работает это следующим образом. После окончания загрузки данных возникает событие loadComplete: и вызывается функция. Эта функция (var udata = $(‘#table’).jqGrid(‘getUserData’); ) получает пользовательские данные из ответа сервера, об этом немного ниже, в виде JSON объекта в данном случае и выводит эти данные на нижнюю панель ($(‘#tb_table’)) в виде HTML выравнивая по правому краю (css(‘text-align’,'right’)). После чего выполняется объявление обработчика используя метод live.
Ну откуда же берутся эти пользовательские данные? С сервера как и все остальные! Вот например как сделал я

$userdata = $_GET['userdata'];
// Выполним запрос, который вернет суммарное кол-во записей в таблице
$result = mysql_query("SELECT COUNT(*)AS count, SUM(region_code) AS sum FROM cities");
if($userdata){
            $data['userdata']['msg'] = '<span style="font-weight: normal; color: red;">Сумма всех чисел в столбце <em>"region_code"<em> равна</span> ';
            $data['userdata']['sum_regions_numbers'] = '<em>'. $row['sum'].'<em>';
            $data['userdata']['button'] = '<input id="show_sum" type="button" value="'.$row['sum'].'">';
        }
// Строки данных для таблицы
        $i = 0;
        while($row = mysql_fetch_assoc($result)) {
            $data['rows'][$i]['id'] = $row[id];
            $data['rows'][$i]['cell'][] = $row[country_code];
            }
            echo json_encode($data);

Итак я запрашиваю серверный скрипт (url:’p2e1.php?userdata=true’), который выполняет запрос. После выполнения запроса, вместе с суммарным кол-вом записей получаем сумму всех значений полей region_code. Далее полученные данные помещаем в массив $data и кодируем в формат JSON.
IV. Управление столбцами данных
1) Изменение размера и положения столбцов
На самом деле никаких манипуляций для реализации этих возможностей таблицы делать не придется. Возможно вы заметили что в листинге предыдущего примера есть не рассмотренное свойство sortable: true и если схватить за заголовок любого из столбцов, то можно drag’n'drop’ом переместить его на место другого столбца. Определение этого свойства как true как раз и включает возможность перетаскивать столбцы. Но перед использованием этой опции плагина убедитесь:

  • Что вы послушали мой совет в первой части и при скачивании архива с прагином в Download Builder вы выставили все галки в том числе jQuiery UI addons.
  • Что вы подключили к странице jQueryUI,а именно виджет sortable.

При этом можно изменять ширину любых столбцов, в colModel-опциях которых не определено свойство resizable: false как столбец «Широта» в ДЕМО2.7, при условии что вы скачали jqGrid с опцией jQuiery UI addons.
2) Скрываем не нужные или отображаем нужные столбцы данных
Начнем обсуждение с ДЕМО2.8.

<link rel="stylesheet" type="text/css" media="screen" href="../../../_library/css/ui.multiselect.css" />
<script type="text/javascript" src="../../../_library/js/ui.multiselect.js"></script>
    <script type="text/javascript">
$(function(){
      var table = $('#table');
      table.jqGrid({
                  url:'p2e1.php',
                  datatype: 'json',
                  mtype: 'GET',
                  colNames:['Код страны','Код региона', 'Город','Долгота','Широта','nbip'],
                  colModel :[
                    {name:'country_code', index:'country_code', width:80, hidden: true},
                    {name:'region_code', index:'region_code', width:80, hidden: true},
                    {name:'city', index:'city', width:90},
                    {name:'latitude', index:'latitude', width:60},
                    {name:'longitude', index:'longitude', width:60},
                    {name:'nbip', index:'nbip', width:30, hidden: true}],
                  pager: $('#tablePager'),
                  toolbar: [true,"top"],
                  sortname: 'city',
                  sortorder: 'asc',
                  caption: 'Управление видимостью столбцов',
                  width: 400
        });

    var tBar = $("#t_table");
    tBar.append('<input id="c_chooser1" type="button" value="Базовый мастер">');
    tBar.append('<input id="c_chooser2" type="button" value="Сторонний мастер">');

    $("#c_chooser1").click(function(){
        table.jqGrid('setColumns',{
                                   colnameview:false,
                                   updateAfterCheck: true
                                  });
    });

    $("#c_chooser2").click(function(){
        table.jqGrid('columnChooser');
    });

});
</script>

Первое что бросается в глаза так это то, что не все столбцы показаны, хотя все объявлены. Эта опция будет полезна если у вас имеется очень много колонок, при этом обычно не все они нужны, но могут понадобится при более детальном рассмотрении каких-то строк. Сделать столбец не видимым при инициализации таблицы можно указав в colModel колонки свойство hidden: true. Но спрятанные колонки нужно как-то показывать при необходимости. Для таких целей можно воспользоваться 2 способами.

  • Использовать метод setColumns, я предпочитаю этот метод ввиду его простоты, не часто нужно управлять столбцами, но если нужно то этот метод самое оно.
  • Использовать метод-плагин columnChooser – этот подходя для истинных гурманов эстетов, очень эффектен если подключить соответствующие файлы. Для начала скачиваем плагин UI.MultiSelect и подключаем файлы ui.multiselect.css и ui.multiselect.js как в демо. И снова напомню что для этого метода jqGrid должна быть с модулями jQuiery UI addons.

Послесловие
В данной статье мы рассмотрели очень много вспомогательных возможностей плагина-таблицы jqGrid, при этом мы пересекли черту «начального использования» таблицы, от всей души поздравляю! Мы хорошо потрудились и дальше нас ждет еще больше интересного, а именно:

  • jqGrid и «деревья»
    • jqGrid и MySQL деревья
    • jqGrid и статические деревья
  • Связывание данных в jqGrid
    • Простая подтаблица (subgrid)
    • jqGrid как subgrid
    • Ведущая и ведомая jqGrid
    • Перемещение строк данных между таблицами
google.com bobrdobr.ru del.icio.us technorati.com linkstore.ru news2.ru rumarkz.ru memori.ru moemesto.ru