jQuery DataTables фильтрация данных

Замечательным плагином datatables я пользуюсь уже давно. В один прекрасный момент встал вопрос о фильтрации и сортировке данных, у которых тип отличается от стандартных (строка, число, html и т.д). Задачка решается довольно быстро — хватило внимательного чтения документации и немного фантазии.

Условие.

Есть таблица на три колонки — просто строка, размер файла/папки и количество дисков. Надо сделать возможность сортировки и фильтрации по каждой колонке (для 2 и третьей колонки надо сделать фильтрации по условиям <, >, =). Так же необходимо сделать фильтрацию по нескольким колонкам.

Решение.

Для тестов создадим набор данных в виде массива:

var aDataSet = [
	['Win 95+', '4KB', 6], 
	['Win 95+',  '54.3MB', 7], 
	['Win 98+', '31KB', 5], 
	['Win XP SP2+', '95.5KB', 1], 
	['Win XP', '357.4KB', 4], 
	['Win 98+ / OSX.2+',  '873.6MB', 3], 
	['Win 98+ / OSX.2+',  '11KB', 5], 
	['Win 98+ / OSX.2+',  '42MB', 7], 
	['Win 2k+ / OSX.3+',  '1.4KB', 2], 
	['OSX.2+',  '408MB', 4], 
	['OSX.3+',  '367MB', 2], 
	['Win 95+ / Mac OS 8.6-9.2',  '54KB', 3], 
	['Win 98SE+',  '263MB',  1], 
];

Теперь проинициализруем создание dataTable:

table = $('#dataTable').dataTable({
	"aaData": aDataSet,
	"aoColumns": [
		{"sType": "string"},
		{"sType": "bandwidth"},
		{"sType": "number"}
	],
	"aaSorting": [],	
	"bSortCellsTop": true,
	"iDisplayLength": 10
});

Здесь мы указываем источник данных (aaData), типы колонок (bandwidth — «пользовательский» тип). Про остальные параметры можно прочитать в оф. документации. Создадим базовую разметку таблицы:

<table cellpadding="0" cellspacing="0" border="0" class="display" id="dataTable">
	<thead>
		<tr>
			<th>
				OS
			</th>
			<th>
				Size
			</th>
			<th>
				Count
			</th>
		</tr>
		<tr>
			<th>
				<input type="text" name="os_filter" id="os_filter" value="" />
			</th>
			<th>
				<input type="text" name="bandwidth_filter" id="bandwidth_filter" value="" />
			</th>
			<th>
				<input type="text" name="count_filter" id="count_filter" value="" />
			</th>
		</tr>
	</thead>
	<tbody>
	</tbody>
</table>

Мы сразу создали три поля для фильтрации данных. Надо повесить на них обработчики ввода текста:

$('#os_filter').keyup(function() {
  table.fnFilter($(this).val(), 0);
});
$('#bandwidth_filter').keyup(function() {
  table.fnFilter('', 1);
});
$('#count_filter').keyup(function() {
  table.fnFilter('', 2);
});

Для принудительной фильтрации вызывается метод fnFilter. Первым параметром передается искомое значение, а вторым — номер колонки, в которой ищем. Так как для колонки OS используется стандартная фильтрация, в функции fnFilter передается значение из поля #os_filter. Для колонок bandwidth, count мы напишем свои фильтры, так что в стандартную функцию передаем пустое значение. Так наш метод будет вызван после стандартного, то нам нужно получить весь набор данных из колонки, а не обработанный.

Наши методы небходимо включить в конструкцию (см. док):

jQuery.extend($.fn.dataTableExt.afnFiltering.push(
    function (oSettings, aData, iDataIndex) {
   .....
  })
);

Объявим наши фильтры:

var inputFilters = [
	{iColumn: 1, elementId: 'bandwidth_filter', type: 'bandwidth' },
	{iColumn: 2, elementId: 'count_filter', type: 'count' }
 ];

В цикле будем обходить весь этот массив и сверять тип данных с типом в массиве inputFilters:

for (i = 0; i < inputFilters.length; i++) {
	  var value = jQuery('#' + inputFilters[i].elementId).val();
        switch (inputFilters[i].type) {
          case 'bandwidth':
            if (value && match) {
              bandwidthFilter(value, aData[inputFilters[i].iColumn]);
            }
            break;
		case 'count':
            if (value && match) {
              countFilter(value, aData[inputFilters[i].iColumn]);
            }
            break;
        }
      }

А теперь опишем функции bandwidthFilter и countFilter.

function countFilter(searchValue, rowValue) {
        var compareChar = searchValue.charAt(0);
        var compareValue = parseFloat(searchValue.substr(1, searchValue.length - 1));
        rowValue = (jQuery(rowValue).text()) ? jQuery(rowValue).text() : rowValue;
        match = false;
        switch (compareChar) {
          case '<':
            if (compareValue > rowValue) match = true;
            break;
          case '>':
            if (compareValue < rowValue) match = true;
            break;
          case '=':
            if (compareValue == rowValue) match = true;
            break;
          default:
            if (searchValue == rowValue) match = true;
        }
      }

По условию первым символом в searchValue может быть <,>, = или цифра (мы сделам так, что если символ сравнения не введен, то по умолчанию будет проверяться простое равенство). match — это переменная, объявленная в рамках функции function (oSettings, aData, iDataIndex){}.

function bandwidthFilter(searchValue, rowValue) {
        var compareChar = searchValue.charAt(0);
        var compareScale = searchValue.charAt(searchValue.length - 1);
        var compareValue = isNaN(parseFloat(compareScale)) ? parseFloat(searchValue.substr(1, searchValue.length - 2)) : parseFloat(searchValue.substr(1, searchValue.length - 1));
        switch (compareScale) {
          case 'm':
            compareValue *= 1048576;
            break;
          default:
            compareValue *= 1024;
        }
        rowValue = (jQuery(rowValue).text()) ? jQuery(rowValue).text() : rowValue;
        var convertedRowValue;
        if (rowValue === '<1KB') {
          convertedRowValue = 1;
        } else {
          var rowValueScale = rowValue.substr(rowValue.length - 2, 2);
          switch (rowValueScale) {
            case 'KB':
              convertedRowValue = parseFloat(rowValue)*1024;
              break;
            case 'MB':
              convertedRowValue = parseFloat(rowValue)*1048576;
              break;
          }
        }
        match = false;
        switch (compareChar) {
          case '<':
            if (compareValue > convertedRowValue) match = true;
            break;
          case '>':
            if (compareValue < convertedRowValue) match = true;
            break;
          case '=':
            if (compareValue == convertedRowValue) match = true;
            break;
          default:
            match = false;
        }
      }

Фильтр по размеру файла/папки выглядит немного сложнее. Надо вначале перевести данные в один формат, а потом выполнить сравнение. Все размеры переводятся в байты. В качестве размера проверяемого значения (searchValue) по умолчанию считаются килобайты, но если в конце будет буква m, то значение будет считаться как мегабайты.

Фильтрации закончена. Осталось сделать сортировки. Для полей OS, count подойдет и стандартная сортировка dataTables, а вот для поля bandwidth напишем свою. Наш код необходимо включить в:

jQuery.extend(jQuery.fn.dataTableExt.oSort, {
  ....
});

Документация говорит, что необходимо сделать три метода: » bandwidth-pre», » bandwidth-asc», » bandwidth-desc». Первый выполняет преобразование данных для сравнения, а второй и третий возвращают результат сравнения двух значений при сортировки по возрастанию и убыванию.

"bandwidth-pre": function (bandwidth) {
    bandwidth = (jQuery(bandwidth).text()) ? jQuery(bandwidth).text() : bandwidth;
    var bytes;
    if (bandwidth === '<1KB') {
      convertedRowValue = 1;
    } else {
      var scale = bandwidth.substr(bandwidth.length - 2, 2);
      switch (scale) {
        case 'KB':
          bytes = parseFloat(bandwidth)*1024;
          break;
        case 'MB':
          bytes = parseFloat(bandwidth)*1048576;
          break;
      }
    }
    return bytes;
  },
  "bandwidth-asc": function (a, b) {
    return a - b;
  },
  "bandwidth-desc": function (a, b) {
    return b - a;
  }

Результат.

Сделано сортировки и фильтрации для каждой колонки в таблице, предусмотрено фильтры по условию «больше», «меньше», «равно», а так же из коробки получена возможность сортировки по нескольких колонкам.

Демо, Скачать код.
datatables

, , , , ,

Оставить комментарий

Top ↑ | Main page | Back