I have the code below which filters the values within HTML table based on selected values from a dropdown. It’s supposed to work pretty much like the filters in Excel.
$(document).ready(function() {
$("table th").click(function() {
showFilterOption(this);
});
});
var arrayMap = {};
function showFilterOption(tdObject) {
var filterGrid = $(tdObject).find(".filter");
if (filterGrid.is(":visible")) {
filterGrid.hide();
return;
}
$(".filter").hide();
var index = 0;
filterGrid.empty();
var allSelected = true;
filterGrid.append(
'<div><input id="all" type="checkbox" style="width: 10% !important" checked>All</div>'
);
var $rows = $(tdObject).parents("table").find("tr");
var values = [];
$rows.each(function(ind, ele) {
if (ind > 0) {
var currentTd = $(ele).children()[$(tdObject).attr("index")];
if (!values.includes(currentTd.innerHTML)) {
values.push(currentTd.innerHTML);
var div = document.createElement("div");
div.classList.add("grid-item");
var str = $(ele).is(":visible") ? "checked" : "";
if ($(ele).is(":hidden")) {
allSelected = false;
}
div.innerHTML =
'<br><input type="checkbox" ' + str + " >" + currentTd.innerHTML;
filterGrid.append(div);
arrayMap[index] = ele;
index++;
}
}
});
if (!allSelected) {
filterGrid.find("#all").removeAttr("checked");
}
filterGrid.append(
'<div style="text-align: center"><input id="close" type="button" value="Close" style="width: 40%"/><input id="ok" type="button" value="Ok" style="width: 40%"/></div>'
);
filterGrid.show();
var $closeBtn = filterGrid.find("#close");
var $okBtn = filterGrid.find("#ok");
var $checkElems = filterGrid.find("input[type='checkbox']");
var $gridItems = filterGrid.find(".grid-item");
var $all = filterGrid.find("#all");
$closeBtn.click(function() {
filterGrid.hide();
return false;
});
$okBtn.click(function() {
filterGrid.find(".grid-item").each(function(ind, ele) {
if ($(ele).find("input").is(":checked")) {
$(arrayMap[ind]).show();
} else {
$(arrayMap[ind]).hide();
}
});
filterGrid.hide();
return false;
});
$checkElems.click(function(event) {
event.stopPropagation();
});
$gridItems.click(function(event) {
var chk = $(this).find("input[type='checkbox']");
$(chk).prop("checked", !$(chk).is(":checked"));
});
$all.change(function() {
var chked = $(this).is(":checked");
filterGrid.find(".grid-item [type='checkbox']").prop("checked", chked);
});
filterGrid.click(function(event) {
event.stopPropagation();
});
return filterGrid;
}
table {
margin: 0 auto;
margin-top: 20px;
width: 100%;
position: relative;
overflow: auto;
overflow-y: overlay;
}
th,
thead {
position: sticky;
top: 0;
border: 1px solid #dddddd;
background-color: #1f2d54;
text-align: center;
color: white;
table-layout: fixed;
word-break: break-word;
height: 45px;
}
.filter {
position: absolute;
width: 20vw;
height: 30vh;
display: none;
text-align: left;
font-size: small;
z-index: 9999;
overflow: auto;
background: #ffffff;
color: #1f2d54;
border: 1px solid #dddddd;
}
.filter input {
margin: 5px !important;
padding: 0 !important;
width: 10%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table style='padding: 8px;'>
<tr>
<th index=0>Email
<div class="filter"></div>
</th>
<th index=1>Name
<div class="filter"></div>
</th>
<th index=2>Level
<div class="filter"></div>
</th>
<th index=3>Location
<div class="filter"></div>
</th>
</tr>
<tr>
<td>Email 1</td>
<td>Name 1</td>
<td>Level 1</td>
<td>Location 2</td>
</tr>
<tr>
<td>Email 1</td>
<td>Name 1</td>
<td>Level 1</td>
<td>Location 1</td>
</tr>
<tr>
<td>Email 2</td>
<td>Name 1</td>
<td>Level 2</td>
<td>Location 1</td>
</tr>
<tr>
<td>Email 3</td>
<td>Name 2</td>
<td>Level 2</td>
<td>Location 1</td>
</tr>
<tr>
<td>Email 3</td>
<td>Name 3</td>
<td>Level 1</td>
<td>Location 2</td>
</tr>
<tr>
<td>Email 1</td>
<td>Name 2</td>
<td>Level 2</td>
<td>Location 1</td>
</tr>
Currently, it shows the unique values of the table in the dropdown, but only filters out one of those values from the table. Any help would be highly appreciated regarding how I could make it filter all the matching values from the table.
asked Sep 28, 2021 at 7:28
You can instead use a ready-made, drop down table filter, ddtf.js
.
(function($) {
$.fn.ddTableFilter = function(options) {
options = $.extend(true, $.fn.ddTableFilter.defaultOptions, options);
return this.each(function() {
if($(this).hasClass('ddtf-processed')) {
refreshFilters(this);
return;
}
var table = $(this);
var start = new Date();
$('th:visible', table).each(function(index) {
if($(this).hasClass('skip-filter')) return;
var selectbox = $('<select class="form-control">');
var values = [];
var opts = [];
selectbox.append('<option value="--all--">' + $(this).text() + '</option>');
var col = $('tr:not(.skip-filter) td:nth-child(' + (index + 1) + ')', table).each(function() {
var cellVal = options.valueCallback.apply(this);
if(cellVal.length == 0) {
cellVal = '--empty--';
}
$(this).attr('ddtf-value', cellVal);
if($.inArray(cellVal, values) === -1) {
var cellText = options.textCallback.apply(this);
if(cellText.length == 0) {cellText = options.emptyText;}
values.push(cellVal);
opts.push({val:cellVal, text:cellText});
}
});
if(opts.length < options.minOptions){
return;
}
if(options.sortOpt) {
opts.sort(options.sortOptCallback);
}
$.each(opts, function() {
$(selectbox).append('<option value="' + this.val + '">' + this.text + '</option>')
});
$(this).wrapInner('<div style="display:none">');
$(this).append(selectbox);
selectbox.bind('change', {column:col}, function(event) {
var changeStart = new Date();
var value = $(this).val();
event.data.column.each(function() {
if($(this).attr('ddtf-value') === value || value == '--all--') {
$(this).removeClass('ddtf-filtered');
}
else {
$(this).addClass('ddtf-filtered');
}
});
var changeStop = new Date();
if(options.debug) {
console.log('Search: ' + (changeStop.getTime() - changeStart.getTime()) + 'ms');
}
refreshFilters(table);
});
table.addClass('ddtf-processed');
if($.isFunction(options.afterBuild)) {
options.afterBuild.apply(table);
}
});
function refreshFilters(table) {
var refreshStart = new Date();
$('tr', table).each(function() {
var row = $(this);
if($('td.ddtf-filtered', row).length > 0) {
options.transition.hide.apply(row, options.transition.options);
}
else {
options.transition.show.apply(row, options.transition.options);
}
});
if($.isFunction(options.afterFilter)) {
options.afterFilter.apply(table);
}
if(options.debug) {
var refreshEnd = new Date();
console.log('Refresh: ' + (refreshEnd.getTime() - refreshStart.getTime()) + 'ms');
}
}
if(options.debug) {
var stop = new Date();
console.log('Build: ' + (stop.getTime() - start.getTime()) + 'ms');
}
});
};
$.fn.ddTableFilter.defaultOptions = {
valueCallback:function() {
return encodeURIComponent($.trim($(this).text()));
},
textCallback:function() {
return $.trim($(this).text());
},
sortOptCallback: function(a, b) {
return a.text.toLowerCase() > b.text.toLowerCase();
},
afterFilter: null,
afterBuild: null,
transition: {
hide:$.fn.hide,
show:$.fn.show,
options: []
},
emptyText:'--Empty--',
sortOpt:true,
debug:false,
minOptions:2
}
})(jQuery);
$('table').ddTableFilter();
table {
margin: 0 auto;
margin-top: 20px;
width: 100%;
position: relative;
overflow: auto;
overflow-y: overlay;
}
th,
thead {
position: sticky;
top: 0;
border: 1px solid #dddddd;
background-color: #1f2d54;
text-align: center;
color: white;
table-layout: fixed;
word-break: break-word;
height: 45px;
}
.filter {
position: absolute;
width: 20vw;
height: 30vh;
display: none;
text-align: left;
font-size: small;
z-index: 9999;
overflow: auto;
background: #ffffff;
color: #1f2d54;
border: 1px solid #dddddd;
}
.filter input {
margin: 5px !important;
padding: 0 !important;
width: 10%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table style='padding: 8px;'>
<tr>
<th index=0>Email
<div class="filter"></div>
</th>
<th index=1>Name
<div class="filter"></div>
</th>
<th index=2>Level
<div class="filter"></div>
</th>
<th index=3>Location
<div class="filter"></div>
</th>
</tr>
<tr>
<td>Email 1</td>
<td>Name 1</td>
<td>Level 1</td>
<td>Location 2</td>
</tr>
<tr>
<td>Email 1</td>
<td>Name 1</td>
<td>Level 1</td>
<td>Location 1</td>
</tr>
<tr>
<td>Email 2</td>
<td>Name 1</td>
<td>Level 2</td>
<td>Location 1</td>
</tr>
<tr>
<td>Email 3</td>
<td>Name 2</td>
<td>Level 2</td>
<td>Location 1</td>
</tr>
<tr>
<td>Email 3</td>
<td>Name 3</td>
<td>Level 1</td>
<td>Location 2</td>
</tr>
<tr>
<td>Email 1</td>
<td>Name 2</td>
<td>Level 2</td>
<td>Location 1</td>
</tr>
answered Sep 28, 2021 at 7:33
Lakshaya U.Lakshaya U.
1,0215 silver badges21 bronze badges
- Download source files — 1.6 KB
Demo
<script language=»javascript»></script>
<input id=»chk» önclick=»enableFilter();» type=»checkbox» name=»chk» />Enable Filter
Col1 | Col2 |
---|---|
1 | string |
1 | string2 |
2 | String |
2 | STRING2 |
3 | |
1 | string |
1 | string2 |
2 | String |
2 | STRING2 |
3 |
Introduction
When I was writing a web application, I needed a way to filter a large table in a simple manner. The users of the application are used to the auto filtering in MS Excel, so I wanted my filter to have the same look and feel.
Features
- Once a column is filtered, the dropdown boxes for the rest of the columns are adapted to the changes. Just like the auto filter in Excel works!
- If a row has the class
noFilter
, the row will not be touched by the filter.
Using the code
Using the code is very simple. Just include the script to the page:
<script language="javascript" src="tablefilter.js"></script>
And activate the filter in the OnLoad
:
<body onload="attachFilter(document.getElementById('tbl'), 1)">
attachFilter
expects two parameters:
- The table object to attach the filter to.
- The row number at which the filter row should be inserted.
Browser Compatibility
The script was initially written for IE. I did test it successfully on Firefox, but I do not know if the script works for Netscape browsers.
History
- 2005/07/27: First version.
This member has not yet provided a Biography. Assume it’s interesting and varied, and probably something to do with programming.
а) в первой (нулевой индекс) строке таблицы — поля для ввода фильтров
б) во второй (первый индекс) строке таблицы — её шапка (наименования столбцов)
в) начиная с третьей (со второго индекса и до конца таблицы) строки в ячейках уже идут данные, кои надо фильтровать
принцип:
1. на поле для ввода фильтра «навешиваете» обработчик либо события
onchange=»myFunc (this)» (для поля типа <select>) либо события onpaste=»myFunc (this)» (для поля типа <input>)
2. функция
myFunc (field) первым делом перебором родителей доходит до тега <TD>, в котором и находится тот самый передаваемый функции this (т.е. поле для ввода фильтра) и определяет zero-index номера столбца (т.е. номер его слева-направо, начиная с нулевого)
3. затем функция перебирает коллекцию строк таблицы, начиная
со второго индекса и до конца таблицы, и в нужном столбце каждой строки сравнивает значения innerHTML ячейки с this.value:
— если значения совпадают, то соответствующей строке устанавливается style.display = ‘block’;
— если значения не совпадают, то этой строке устанавливается style.display = ‘none’;
вот и всё — примитивно и просто
определение функции
myFunc (field) нужно всего одно на странице
и обрабатывать она сможет любое количество фильтруемых столбцов любого количества таблиц страницы
никаких id и class‘ов для таблиц, строк и ячеек прописывать не надо
с кодом функции сами справитесь?
GitHub pages makes it easy to share information: just send the URL instead of emailing a file attachment. When I wanted to share the contents of an Excel file this was a natural platform, but with over 1,000 rows of data I needed a way to filter the table on the webpage.
With my knowledge at the time limited to some basic HTML and very little JavaScript, this is an exercise in hacking together a solution. Keep reading to see how I implemented a solution using the TableFilter JavaScript library.
Requirements & Research
With our data to share in a local spreadsheet, the basic requirement is the ability to filter a table on a website on multiple columns just as you can in a spreadsheet:
Being comfortable in Python my first instinct is to filter a Pandas DataFrame. But we are hosting this on GitHub pages as a static website and unable to run the filtering server-side. Therefore, we’ll use JavaScript to filter the table client-side in the browser.
I was able to find a number of examples that provide basic filtering capability with JavaScript, but these are limited to filtering on one column. Eventually I came across the TableFilter JavaScript library, which has great documentation and plenty of examples.
Using TableFilter
To get started, I cloned TableFilter into my repository:
git clone https://github.com/koalyptus/TableFilter.git
We will edit index.html
, the HTML file that holds our table and uses tablefilter.js
to perform the filtering.
├── assets
├── index.html
└── tablefilter
└── tablefilter.js
The strategy I used to get a working product is simple and applicable to more general technical challenges:
- Start with a working example that does approximately what you need or more
- Remove or modify features to better align with your use case
- Repeat step 2 until you have what you want
The key here is maintaining a working example throughout and taking a step back if you break something. Iterating a few times on the index.html
I borrowed from one of the basic examples, I was left with this:
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Table Filter Example</title>
<!-- Bootstrap core CSS -->
<link rel="stylesheet" href="assets/css/bootstrap.min.css">
<body>
<!-- Header -->
<section id="header">
<header>
<h2>Filter Table Example</h2>
</header>
<!-- TABLE CODE START -->
<table id="demo" border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th>First</th>
<th>Last</th>
<th>Birthday</th>
<th>Age</th>
<th>Color</th>
<th>Height</th>
<th>Weight</th>
<th>IQ</th>
</tr>
</thead>
<tbody>
<tr>
<td>ZOE</td>
<td>DAVIS</td>
<td>2012-03-12</td>
<td>6</td>
<td>Yellow</td>
<td>67</td>
<td>108</td>
<td>81</td>
</tr>
...
</tbody>
</table>
<!-- TABLE CODE END -->
</section>
</body>
</head>
<script src="tablefilter/tablefilter.js"></script>
<script data-config="">
var filtersConfig = {
base_path: 'tablefilter/',
auto_filter: {
delay: 110 //milliseconds
},
filters_row_index: 1,
state: true,
alternate_rows: true,
rows_counter: true,
btn_reset: true,
status_bar: true,
msg_filter: 'Filtering...'
};
var tf = new TableFilter('demo', filtersConfig);
tf.init();
</script>
You can view the original code or a live example of the final product.
Customize this by including the HTML defining the table between <!-- TABLE CODE START -->
and <!-- TABLE CODE END -->
(easy to automate with Python if you need to update the data often). Just below the table definition, we call the tablefilter.js
script and define the configuration items.
This leaves us with an easy to filter table:
Closing Thoughts
Is this the best way to share data? Certainly not. But it was a quick solution to a problem I had in a situation (work) where speed and ease are valued at a premium. Furthermore this solution utilizes existing GitHub pages infrastructure and a great open source library.
I hope this example either provides you with a quick solution to a problem I previously had or demonstrates how you may be able to hack together a solution by iterating on a similar working example you can find online.
- All names in this dataset are fake. Any resemblance to real persons, living or dead, is purely coincidental…I made up some data since the data motivating this example is proprietary.
- You can view the original code or a live example of the final product.
- While writing this up I discovered Brython, an implementation of Python 3 in the browser. This is worth checking out in the future.
Как сделать — Фильтра/поиска таблицы
Узнать, как создать фильтр таблицы с помощью JavaScript.
Фильтр таблицы
Как использовать JavaScript для поиска определенных данных в таблице.
Имя | Страна |
---|---|
Alfreds Futterkiste | Германия |
Berglunds snabbkop | Швеция |
Island Trading | Великобритания |
Koniglich Essen | Германия |
Laughing Bacchus Winecellars | Канада |
Magazzini Alimentari Riuniti | Италия |
North/South | Великобритания |
Paris specialites | Франция |
Редактор кода »
Создание отфильтрованную таблицу
Шаг 1) Добавить HTML:
Пример
<input type=»text» id=»myInput» onkeyup=»myFunction()» placeholder=»Поиск имен..»>
<table id=»myTable»>
<tr class=»header»>
<th style=»width:60%;»>Имя</th>
<th style=»width:40%;»>Страна</th>
</tr>
<tr>
<td>Alfreds Futterkiste</td>
<td>Германия</td>
</tr>
<tr>
<td>Berglunds snabbkop</td>
<td>Швеция</td>
</tr>
<tr>
<td>Island Trading</td>
<td>Великобритания</td>
</tr>
<tr>
<td>Koniglich Essen</td>
<td>Германия</td>
</tr>
</table>
Шаг 2) Добавить CSS:
Стиль входного элемента и таблицы:
Пример
#myInput {
background-image: url(‘/css/searchicon.png’); /* Добавить значок поиска для ввода */
background-position: 10px 12px; /* Расположите значок поиска */
background-repeat: no-repeat; /* Не повторяйте изображение значка */
width: 100%; /* Полная ширина */
font-size: 16px; /* Увеличить размер шрифта */
padding: 12px 20px 12px 40px; /* Добавить немного отступов */
border: 1px solid #ddd; /* Добавить серую границу */
margin-bottom: 12px; /* Добавить некоторое пространство под входом */
}
#myTable {
border-collapse: collapse; /* Свернуть границы */
width: 100%; /* Полная ширина */
border: 1px solid #ddd; /* Добавить серую границу */
font-size: 18px; /* Увеличить размер шрифта */
}
#myTable th, #myTable td {
text-align: left; /* Выравнивание текста по левому краю */
padding: 12px; /* Добавить отступ */
}
#myTable tr {
/* Добавить нижнюю границу для всех строк таблицы */
border-bottom: 1px solid #ddd;
}
#myTable tr.header, #myTable tr:hover {
/* Добавить серый цвет фона для заголовка таблицы и при наведении курсора мыши */
background-color: #f1f1f1;
}
Шаг 3) Добавить JavaScript:
Пример
<script>
function myFunction() {
// Объявить переменные
var input, filter, table, tr, td, i, txtValue;
input = document.getElementById(«myInput»);
filter = input.value.toUpperCase();
table = document.getElementById(«myTable»);
tr = table.getElementsByTagName(«tr»);
// Перебирайте все строки таблицы и скрывайте тех, кто не соответствует поисковому запросу
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName(«td»)[0];
if (td) {
txtValue = td.textContent || td.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = «»;
} else {
tr[i].style.display = «none»;
}
}
}
}
</script>
Редактор кода »
Совет: Удалить toUpperCase() если вы хотите выполнить поиск с учетом регистра.
Совет: Изменить tr[i].getElementsByTagName(‘td’)[0]к [1] если вы хотите найти «Страна» (индекс 1) вместо «имя» (индекс 0).
Совет:Кроме того, проверить Фильтр списка.