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.
CodePudding user response:
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>