Сегодня, передо мной была поставлена задача навигации по строкам таблицы c помощью клавиатуры в primefaces. После изучения сатйов primefaces и primefaces extensions выяснилось, что данная возможность не реализована.
На форуме нам предлагают самим реализовать эту функциональность, так как:
Предположим у нас есть следующая таблица:
Если мы сейчас запустим наше приложение и попробуем нажать клавишу вниз, то ничего не произойдет, так как табица не в фокусе, и это хорошо. Теперь выделим любую строку в нашей таблице и нажмем клавишу вниз - выделение перешло на следующую строчку - супер!
В эйфории мы продолжаем щелкать клавишу вниз, но тут обнаруживается, что выделенная строка не меняется. Что же произошло? А то, что метод selectRow(int index), почему-то не обновляет originRowIndex. Ну что же, придется сделать этого за него. Добавляем в конец нашего кода следующую строчку:
На форуме нам предлагают самим реализовать эту функциональность, так как:
This feature doesn't have high priority at the moment unless someone sponsors it.
что переводится как:На данный момент, данная функциональность имеет низкий приоритет и не будет
реализована пока ее кто-нибудь не оплатит.
(от автора: видимо очень низкий, дата поста 21.06.2012)
В тикете на багтрекере, есть вариант реализации данной задачи, но он плох тем, что генерирует лишние запросы на сервер и лишний трафик. Так как больше вариантов найдено не было, я решил написать собственный (ну и само собой поделиться им с вами). Для реализации это задачи нам понадобиться primefaces версии 4+. Я не буду описывать создание всего приложения, а опишу только как добавить возможность навигации для datatable. Просмотреть и загрузить весь проект вы можете на GitHub.Предположим у нас есть следующая таблица:
<p:dataTable id="dataTable" widgetVar="table" ...>
...
</p:dataTable>
Для обработки нажатий клавиш на клавиатуре, мы могли бы использовать компонент primefaces <p:hotkey ...>
. Но в этом случае клавиши переназначались бы для всей страницы, а нам необходимо их оставить для других компонентов или для скролла в браузере, поэтому будем использовать jquery. Для того чтобы повесить обработчик на таблицу, нам необходимо добавить к ней аттрибут tabindex, но разработчики primefaces лишили нас этой возможности, поэтому я решил особо не заморачиваться и обернул таблицу в div с аттрибутом tabindex = 1, вот так:<div tabindex="1" id="table_div">
<p:dataTable id="dataTable" widgetVar="table" ...>
...
</p:dataTable>
</div>
Теперь мы можем вешать обработчик событий с клавиатуры на нашу таблицу. Кроме того, благодаря tabindex, эти события будут перехватываться только тогда, когда таблица находиться в фокусе. Напишем обработчик клавиши вниз:$("#table_div").keydown(function(event) {
if (event.which === 40) {
event.preventDefault();
alert("You press down key.")
}
});
Теперь напишем функцию, которая будет выделять следующую строку в таблице и заменем бессмысленный alert на вызов этой функции:var down = function() {
//Получаем индекс выбранной строки, если строка не выбрана вернет 0
var index = PF('table').originRowIndex;
//увеличиваем индекс на 1
index++;
//убираем выделение со всех строк
PF('table').unselectAllRows();
//выделяем новую строку
PF('table').selectRow(index);
};
Как видно из кода мы используем методы объекта, возвращаемого PF(‘table’), где “table” - это имя виджета widgetVar. Если мы сейчас запустим наше приложение и попробуем нажать клавишу вниз, то ничего не произойдет, так как табица не в фокусе, и это хорошо. Теперь выделим любую строку в нашей таблице и нажмем клавишу вниз - выделение перешло на следующую строчку - супер!
В эйфории мы продолжаем щелкать клавишу вниз, но тут обнаруживается, что выделенная строка не меняется. Что же произошло? А то, что метод selectRow(int index), почему-то не обновляет originRowIndex. Ну что же, придется сделать этого за него. Добавляем в конец нашего кода следующую строчку:
...
PF('table').selectRow(index);
//change originRowIndex value
PF('table').originRowIndex = index;
Пробуем… Теперь все работает, но… Когда мы доходим до конца нашей таблицы, выделение пропадает, а точнее уходит за ее пределы. Давайте же исправим это. Для этого воспользуемся количеством дочерних элементов в таблице и наш код теперь выглядит так:var down = function() {
//get index of selected row, if no row is selected return 0
var index = PF('table').originRowIndex;
//get amount of rows in the table
var rows = PF('table').tbody[0].childElementCount;
//increase row index
index++;
//if new index equals number of rows, set index to first row
if (index === rows) {
index = 0;
}
//deselect all selected rows
PF('table').unselectAllRows();
//select new row
PF('table').selectRow(index);
//change originRowIndex value
PF('table').originRowIndex = index;
};
$("#table_div").keydown(function(event) {
if (event.which === 40) {
event.preventDefault();
down();
}
});
Сделаем то же самое для клавиши вверх:var up = function() {
var rows = PF('table').tbody[0].childElementCount;
var index = PF('table').originRowIndex;
if (index === 0) {
index = rows - 1;
} else {
index--;
}
PF('table').unselectAllRows();
PF('table').selectRow(index);
PF('table').originRowIndex = index;
}
$("#table_div").keydown(function(event) {
if (event.which === 38) {
event.preventDefault();
up();
}
if (event.which === 40) {
event.preventDefault();
down();
}
});
Как можно убедить все работает, но есть еще один баг. Если выделить таблицу, щелкнув по ее заголовку, и нажать клавишу вниз, то мы увидим что выделиться вторая строка. Можно было бы конечно оставить так, но не нужно. Испрвить это очень лекго. В виджете таблицы есть поле selection, которое хранит массив выделенных элементов, им мы и воспользуемся. Добавим в начало метода down следующие условие://If no rows selected, select first row
if(PF('table').selection.length === 0){
PF('table').selectRow(0);
return;
}
Вот и все, наша талбица готова. Я также добавил туда возможность выбора элемента нажатием клавиши enter, но не буду описывать это в этой статье. Если есть желание, можете скачать код с GitHub. Также здесь реализована возможность только одиночного выбора, если понадобиться, могу написать статью по множественному.
Комментариев нет:
Отправить комментарий