« Сложные интерфейсы на javascript вместе Yahoo UI. Часть 17 | Сложные интерфейсы на javascript вместе Yahoo UI. Часть 19 » |
Сложные интерфейсы на javascript вместе Yahoo UI. Часть 18
Эта статья завершит рассказ об одном из самых “больших” и полезных компонентов в библиотеке Yahoo UI - компоненте DataTable. DataTable служит для отображения на веб-страницах информации в форме таблиц. В последних двух статьях я рассказал почти обо всех возможностях DataTable. Остались не раскрытыми только те функции DataTable, которые связаны с редактированием содержимого таблицы.В прошлой статье я рассказывал, как можно настроить правила выделения строк в таблице. Как разрешить выделять одну строку, или целый их диапазон, как реализовать динамическую подсветку строки, над которой в этот момент времени находится курсор. Все это было подготовительными шагами для того, чтобы превратить DataTable из средства только отображения табличных данных в инструмент, позволяющий редактировать данные в таблице и даже отправлять информацию назад на сервер (сохранять ее в БД).
Разрешив пользователю выделять в конкретный момент времени только одну строку, я хочу реализовать модель редактирования содержимого таблицы с помощью специальной (моей) панели. Эта панель (состоящая из множества текстовых полей, наборов радио-кнопок, падающих списков) будет расположена ниже самой таблицы с записями. Как только пользователь выделит любую запись в таблице, то элементы управления панели редактирования будут наполнены информацией. А когда пользователь переходит (выделяет) другую запись в таблице, то необходимо изменить внешний вид таблицы и отправить запрос сохранения отредактированной записи на сервер. Каждый из этих шагов имеет свои подводные камни, и может превратиться не в одну сотню строк кода, если делать все качественно. К примеру, должно ли редактирование содержимого некоторого поля на панели внизу таблицы приводить к одновременному изменению содержимого соответствующего столбца таблицы? Следует ли блокировать навигацию пользователя по таблице до тех пор, пока отправленный запрос сохранения исправленной записи на сервер не вернулся с подтверждением “да, все правки были сохранены”. Или, может быть, нужно ставить запрос на сохранение в асинхронную очередь, так чтобы пользователь продолжал работу, а мы бы тем временем могли бы накопить “пачку правок”, чтобы послать их на сервер все вместе. Такой вариант имеет смысл в случае, если количество правок очень велико, равно как и затраты времени на их обработку. Где выполнять валидацию введенных пользователем данных на предмет их корректности, как ее грамотно разделить между клиентом и сервером, так чтобы не нагружать сервер множеством “мелких” запросов, возникающих по мере того, как пользователь редактирует информацию? Как быть если некоторые из полей записи представлены в виде падающих списков, значения которых берутся из базы данных? Следует ли кэшировать эти списки на время всего сеанса работы, а может перезагружать с каким-то интервалом времени или при начале редактирования очередной записи? Следует ли после отправки запроса на сохранение данных на сервер, загружать с него же обновленный перечень записей (то, что могло быть параллельно отредактировано другим пользователем) или изолировать сеансы разных пользователей друг от друга?
Я оставлю все это за кадром и сосредоточусь на ключевых особенностях, именно, YUI: о том, как назначить обработчик события “выделена строка”, как узнать то, какая строка выделена, как извлечь из нее информацию для всех колонок и как “на лету”, без перезагрузки DataTable, изменять содержимое ячеек.
Начнем с простого: создадим заготовку панели редактирования записи. Это будут четыре текстовых поля с идентификаторами (id), имена которых совпадают с именами полей таблицы:
<div id="editorPanel">
fio: <input type="text" id="fio" /> <br />
birthday: <input type="text" id="birthday" /> <br />
sex: <input type="text" id=" sex" /> <br />
salary: <input type="text" id="salary" /> <br />
</div>
table.subscribe("rowSelectEvent", onSelectRow);
function onSelectRow (oArgs){
var el = oArgs['el'];
record = oArgs['record'];
YAHOO.util.Dom.get('fio').value = record.getData ('fio');
// и так для остальных полей
}
Пример не идеален, т.к. при переходе по страницам paginator-а, событие “запись была изменена” не генерируется и, следовательно, панель редактирования отображает устаревшие данные. В следующем примере я подписываюсь на сообщение “renderEvent”, которое выбрасывается всякий раз, когда таблица перерисовывается (при начальной загрузке данных в DataTable, а также при переходе по страницам, изменении направления сортировки). Устройство же функции “onRender” тривиально: я получаю ссылки на всех текстовые поля в панели редактирования и очищаю их.
table.subscribe("renderEvent", onRender);
function onRender (oArgs){
YAHOO.util.Dom.get('fio').value = '';
// и так все остальные поля
}
var lastSelected = null;
var requstedToSelectAfterSaving = null;
function onSelectRow (oArgs){
var dom = YAHOO.util.Dom;
var mustLock = false;
record = oArgs['record'];
if (requstedToSelectAfterSaving != null) return;
if (lastSelected != null){
oldData = this.getRecord (lastSelected).getData();
mustLock = (
dom.get('fio').value != oldData['fio'] ||
dom.get('birthday').value != oldData['birthday'] ||
dom.get('sex').value != oldData['sex'] ||
dom.get('salary').value != oldData['salary']);
}
if (mustLock){
requstedToSelectAfterSaving = this.getLastSelectedRecord ();
alert ('saving data'); // имитация сохранения данных
var lastSelected2 = lastSelected;
lastSelected = null;
this.unselectAllRows ();
this.selectRow ( lastSelected2 );
this.disable (); }
else{
dom.get('fio').value = record.getData ('fio');
dom.get('birthday').value = record.getData ('birthday');
dom.get('sex').value = record.getData ('sex');
dom.get('salary').value = record.getData ('salary');
lastSelected = this.getLastSelectedRecord ();
}
}
Больших проблем этот “бажок” YUI не вызывает, т.к. на момент отправки запроса обойтись просто затемнением DataTable не получается: не красиво и не понятно клиенту, что там происходит с интерфейсом. Я предпочитаю делать так: помещаю и DataTable и paginator внутрь общего блока div. Затем, перед началом отправки запроса, я меняю стилевое оформление контейнера div так, чтобы создать эффект затемнения, закрывающий и DataTable и paginator, а посередине div-а размещается gif картинка с анимацией, например, часов, подсказывающая о том, что сейчас идет выполнение запроса сохранения данных и нужно немного подождать. Теперь, предположим, что запрос сохранения отработал, и никаких ошибок при этом не возникло. Какая информация будет возвращаться из php-скрипта, обслуживающего DataTable, решается в каждом случае индивидуально. Самый простой вариант, когда javascript код в браузере просто получает одно из двух значений: либо “saved”, либо “failed” (была операция сохранения удачной или нет). В некоторых случаях вместе с признаком успешности завершения операции возвращается содержимое записи. Казалось бы, зачем, ведь те же самые данные мы отправили минутой назад на сервер для сохранения? Для “больших” систем характерно хранение данных в таблицах обслуживаемых триггерами или хранимыми процедурами. Триггер вызывается при выполнении операций сохранения записей в таблице и может данные изменить перед их действительным сохранением. А это значит, что данные, которые “ушли” на сервер, могут быть совсем не теми, что были сохранены в таблицах БД. Еще более сложные действия предстоят, когда пользователь изменил значение поля, к которому применена сортировка, например, сменил ФИО сотрудника с “Иванов” на “Сидоров”. В этом случае отредактированная запись не должна отображаться на текущей странице DataTable: нам нужно вернуть с сервера сразу 10 записей (содержимое пересортированной страницы). Не уходя далеко от рассмотрения YUI DataTable, подумаем над тем, как динамически изменять информацию, отображаемую в таблице, без ее полной перезагрузки. Это пригодится не только для приведения внешнего вида таблицы в соответствие с тем, что находится на сервере в таблице БД после сохранения записи, но и для реализации функции “живого редактирования”. Т.е. по мере ввода пользователем нового значения для какого-то из полей таблицы в текстовом поле панели редактирования, внешний вид связанной с этим полем колонки также должен меняться. Делается это очень просто: назначим каждому из текстовых полей в панели редактирования функцию, реагирующую на изменения такого текстового поля:
YAHOO.util.Event.addListener("fio", "keyup", onChangeFIO );
var data = table.getRecord(lastSelected).getData();
data ['fio'] = YAHOO.util.Dom.get('fio').value;
table.updateRow (lastSelected, data);
var reqTd = {record:lastSelected, column: table.getColumn ('fio') }
table.getTdLinerEl(reqTd).innerHTML = YAHOO.util.Dom.get('fio').value;
table.getRecord(lastSelected).setData('fio', YAHOO.util.Dom.get('fio').value);
table.getRecordSet().updateRecordValue (selected, 'fio', YAHOO.util.Dom.get('fio').value);
Я хочу завершить рассказ об DataTable, показав как можно выполнять редактирование ячеек таблицы “inline”. Т.е. при выделении ячейки таблицы, ее внешний вид меняется и на экране показывается компонент редактор (текстовое поле, падающий список). Привязать к любой из колонок таблицы специализированный редактор очень просто. Когда мы создаем массив объектов, описывающий характеристики колонок таблицы, то наряду с такими уже знакомыми нам свойствами как функция форматирования содержимого ячейки, признак того можно ли сортировать колонку, мы можем указать свойство editor (редактор ячейки). В следующем примере (результат выполнения показан на рис. 3) я показываю пример с редактором полей типа “дата-время”, редактор поля в виде диалогового окна с двумя переключателями радио-кнопками для выбора пола сотрудника.
Есть также редактор в виде диалогового окна с набором checkbox-ов, с выпадающим списком вариантов и многое другое:
// как обычно описываем колонки таблицы
var columns = [
{key:"fio", sortable:true},
{key:"birthday", sortable:true, formatter:YAHOO.widget.DataTable.formatDate, editor: new YAHOO.widget.DateCellEditor() },
{key:"sex", editor: new YAHOO.widget.RadioCellEditor({radioOptions:["male","female"], disableBtns:true}) },
{key:"salary", sortable:true}
];
// а по выделению ячейки нужно показать редактор ячейки
table.subscribe("cellClickEvent", table.onEventShowCellEditor);
« Сложные интерфейсы на javascript вместе Yahoo UI. Часть 17 | Сложные интерфейсы на javascript вместе Yahoo UI. Часть 19 » |