« Сложные интерфейсы на javascript вместе Yahoo UI. Часть 16 | Сложные интерфейсы на javascript вместе Yahoo UI. Часть 18 » |
Сложные интерфейсы на javascript вместе Yahoo UI. Часть 17
Эта статья продолжает рассказ об одном из самых часто используемых и сложных компонентов YUI – DataTable. Сегодня я расскажу о том, как загружать данные для DataTable с сервера с поддержкой paging-а, как сделать табличку более дружественной к пользователю и как работать с моделями выделения строк.В прошлый раз я остановился на том, что показал, как DataTable интегрируется с компонентом Paginator для отображения большого объема информации постранично. В самом простом случае DataSource загружает сразу все содержимое таблицы базы данных на сервере в память браузера. И затем Paginator обслуживает (уже мгновенный) переход по страничкам. Во втором случае данные с сервера подтягиваются постепенно, по мере перемещения по страничкам. Это означает, что мы должны на сервере реализовать не только постраничный отбор данных, но и их сортировку. Действительно, при изменении порядка сортировки, например, с “ФИО” на “зарплата” записи, которые отображались на первой странице, могут быть разбросаны по другим страницам. И, наоборот, записи с других страниц (еще не загруженных), должны попасть на первую страницу. Это довольно скользкий момент т.к. резко увеличивается количество обращений к серверу, хотя грамотная система кэширования и может помочь сохранить производительность. Поддержка динамической загрузки данных и сортировка на сервере в YUI DataTable реализуется очень просто: нужно при создании DataTable указать значение “true” для конфигурационной переменной “dynamicData” и все. Теперь DataTable будет формировать запросы к серверному php-скрипту передавая ряд переменных. Во-первых: sort – поле, по которому нужно выполнить сортировку записей. Затем идет направление сортировки (по возрастанию или по убыванию); оно задается переменной dir. Переменные startIndex и results задают, соответственно, позицию записи, с которой идет выборка данных из таблицы БД и еще количество записей, которые нужно отобрать. К счастью, вам вовсе не обязательно завязывать наш php-код на именно эти имена переменных. Более того, YUI может передать нам полную ответственность за формирование http-запроса к серверу. Для этого я переопределяю функцию generateRequest:
function customGenerateRequest (state, table){
state = state || {pagination:null, sortedBy:null};
var sortBy = (state.sortedBy) ? state.sortedBy.key : table.getColumnSet().keys[0].getKey();
descCssName = YAHOO.widget.DataTable.CLASS_DESC;
var sortDir = (state.sortedBy && state.sortedBy.dir === descCssName) ? "desc" : "asc";
var from = (state.pagination) ? state.pagination.recordOffset : 0;
var size = (state.pagination) ? state.pagination.rowsPerPage : 10;
return "sortBy=" + sortBy + "&sortDir=" + sortDir + "&from=" + from + "&size=" + size ;
}
CREATE TABLE `employees` (
`user_id` int(11) NOT NULL AUTO_INCREMENT, `fio` varchar(100) DEFAULT NULL,
`birthday` date DEFAULT NULL, `salary` double DEFAULT NULL, `sex` enum('male','female') DEFAULT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB
mysql_connect ('localhost', 'root', '') or die ('unable to connect to mysql server');
mysql_select_db (‘kadry') or die ('unable to select db');
$from = $_REQUEST['from'];
$size = $_REQUEST['size'];
$sortBy = isset($_REQUEST['sortBy'])?$_REQUEST['sortBy']:"user_id";
$sortDir = isset($_REQUEST['sortDir'])?$_REQUEST['sortDir']:"";
$sql = "select SQL_CALC_FOUND_ROWS * from employees order by $sortBy $sortDir limit $from, $size";
$rez = mysql_query ($sql) or die ('unable to select data' . $sql);
$count = mysql_query ('select FOUND_ROWS()') or die ('unable to calculate total records count');
$count = mysql_fetch_array ($count);
$count = $count[0];
$rows = array ();
while ($row = mysql_fetch_assoc($rez))
$rows [] = $row;
$final = array ('users' => array ('user' => $rows), 'total_records' => $count );
print json_encode ($final);
ds.responseSchema = {
resultsList: "users.user",
fields: [
"fio",
{key:"birthday", parser: strToDate},
"sex",
{key:"salary", parser:"number"}
] ,
metaFields: { total_records: "total_records"}
};
function handlePayload (oRequest, oResponse, oPayload) {
oPayload.totalRecords = parseInt(oResponse.meta.total_records);
return oPayload;
}
table.handleDataReturnPayload = handlePayload;
Теперь займемся дальнейшими улучшениями DataTable. И начнем с того, что попробуем реализовать функцию “спрятать столбец”. Это очень полезная функция, если в таблице очень много колонок и не все из них имеет смысл одновременно показывать. В левом верхнем углу таблицы можно сделать специальную кнопку, по нажатию на которую появляется диалоговое окно. В этом окне вы с помощью checkbox-ов отмечаете то, какие колонки в DataTable нужно спрятать или отобразить. К сожалению, хотя YUI содержит ряд методов для управления видимостью колонок, но “готового из коробки” решения нет (снова пинок в пользу ExtJs). Так что тряхнем стариной (точнее вспомним материал из четвертой статьи серии) и попробуем реализовать диалоговое окно выбора отображаемых колонок сами. Пример мы реализуем по шагам: первым делом я хочу добавить к таблице еще одну фиктивную колонку. Она будет расположена крайней слева и не содержит никакой информации: мне нужен пустой заголовок таблицы, в котором разместится кнопка вызова диалогового окна (описания остальных колонок остались без изменения).
var columns = [
{key:"fake_hide_show", sortable:false, label:'<div id="columnHideShowBtn">�</div>'},
{key:"fio", sortable:true},
… ];
<style>
#columnHideShowBtn {
background:#D8D8DA url(pic_props.png) no-repeat 50% 50%;
cursor: pointer;
width: 24px;
height: 24px;
}
</style>
YAHOO.util.Event.addListener("columnHideShowBtn", "click", doHideShowDialog);
function doHideShowDialog (){
d = new YAHOO.widget.SimpleDialog("placeholderforDialog",
{
width : "400px",
icon: YAHOO.widget.SimpleDialog.ICON_INFO,
fixedcenter : true,
visible : false,
constraintoviewport : true,
buttons : [
{ text:"Accept", handler:onAccept},
{ text:"Discard", handler:onDiscard, isDefault:true}
]
}
);
// настройка внешнего вида диалогового окошка
d.setHeader("Выберите колонки таблицы для отображения");
rez = '<br />';
var defs = table.getColumnSet().getDefinitions();
for (i = 1; i < defs.length; i++){
def = defs[i];
column = table.getColumnSet().getColumn (i);
label = def.label || def.key;
if_checked = column.hidden?'':'checked';
rez+= '<input type="checkbox" id="chk_'+i+'" '+if_checked+'/>' + label + "<br />";
}
d.setBody(rez);
d.render (document.body);
d.show ();
}
function onAccept (e){
var defs = table.getColumnSet().getDefinitions();
for (i = 1; i < defs.length; i++)
if (YAHOO.util.Dom.get('chk_' + i).checked)
table.showColumn (i);
else
table.hideColumn (i);
this.hide ();
}
Таблицы редко используются только для отображения информации – гораздо чаще для ее редактирования. В простейшем случае сама таблица находится в режиме “только для чтения”. Зато по выбору какой-либо строки (неплохо бы это еще и визуально отметить) внизу страницы можно отобразить панель с множеством полей редактирования для колонок таблицы. Этот вариант особенно удобен, если количество отображаемых колонок в таблице гораздо меньше всех, которые есть у записи (и которые может захотеть отредактировать пользователь). На специальной панели должно быть достаточно места для того, чтобы разместить сложные (главное удобные) элементы редактирования. Если количество полей таблицы не велико, и все они умещаются на экране без громоздких горизонтальных прокруток, то можно использовать и inline-редактирование, как если бы мы захотели отредактировать ячейку обычной таблицы ms excel. Давайте попробуем реализовать оба эти варианта и начнем с редактирования содержимого таблицы на специальной панели. Первым шагом я должен настроить режим выделения строк таблицы: т.е. можно ли выделить с нажатой клавишей “ctrl” несколько строк или только одну строку. Создавая DataTable, я передам ее конструктору параметр selectionMode, равный “single”. Это значит, что выделить можно только одну строку. Кроме варианта “single” есть еще “standard” (режим по умолчанию), когда работают клавиши ctrl и shift для выделения нескольких строк. Режим “singlecell” разрешает выделить только одну ячейку таблицы, а режим “cellblock” позволяет вам выделить любые ячейки таблицы, так чтобы они образовывали прямоугольный блок. А режим “cellrange” позволяет выделить несколько последовательно расположенных ячеек таблицы (как будто выделяете диапазон дат на календаре).
table = new YAHOO.widget.DataTable("tableplaceholder", columns, ds, { selectionMode: "single"} );
function onSelectRow (oArgs){
table.onEventSelectRow (oArgs);
}
// и назначаем функции
table.subscribe("rowMouseoverEvent", table.onEventHighlightRow);
table.subscribe("rowMouseoutEvent", table.onEventUnhighlightRow);
table.subscribe("rowClickEvent", onSelectRow);
// выделяем первую строку
table.selectRow(table.getTrEl(0));
« Сложные интерфейсы на javascript вместе Yahoo UI. Часть 16 | Сложные интерфейсы на javascript вместе Yahoo UI. Часть 18 » |