-
Notifications
You must be signed in to change notification settings - Fork 783
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Column filter like handsontable #4225
Comments
Hi, I hope it is useful and that in the future it can be supported natively. <div class="menu-overlay">
<div class="filter-menu">
<button class="close-menu-button">x</button>
<input type="text" id="filter-input" placeholder="Cerca..."></input>
<button id="clear-selection-button"></button>
<button id="select-all-button"></button>
<div id="value-select">
</div>
<button id="remove-filter-button"></button>
<button id="filter-button">OK</button>
</div>
</div> .tabulator-header-popup-button {
padding: 2px 5px 2px 6px;
}
.tabulator-header-popup-button.active{
color: rgba(251, 214, 105);
text-shadow: 1px 1px 3px #000;
}
.menu-overlay {
position: absolute;
z-index: 1;
display: none;
}
.close-menu-button {
position: relative;
float: right;
border-radius: 5px;
}
.close-menu-button:hover{
background-color: #ddd;
}
.filter-menu {
position: absolute;
bottom: 0px;
background-color: #f8f8f8;
padding: 5px;
max-height: 355px;
min-width: 150px;
border: 1px solid #999;
}
.filter-menu > button {
border-radius: 4px;
border-width: 1px;
}
#clear-selection-button {
position: relative;
background: none;
border: none;
color: red;
cursor: pointer;
font-size: 15px;
top: 3px;
}
#select-all-button {
position: relative;
background: none;
border: none;
color: blue;
cursor: pointer;
font-size: 15px;
top: 3px;
}
#value-select {
position: relative;
height: 250px;
width: 200px;
margin: 5px;
overflow: auto;
background-color: #ffffff;
}
#value-select > label {
display: flex;
}
#remove-filter-button {
background: none;
border: none;
font-size: 15px;
color: red;
cursor: pointer;
}
#filter-button {
float: right;
position: relative;
background-color: #f8f8f8;
border-radius: 5px;
}
#filter-button:hover{
background-color: #ddd;
} headerMenu:true, //show advanced filter menu (Set in column properties) // Add filter icon
$(".tabulator-header-popup-button").html('<i class="fas fa-filter"></i>');
var menuOverlay = $('.menu-overlay');
// Clear data on change
var clickedColumn = null;
var filters = [];// Array per memorizzare i filtri per ogni colonna
// Declaration of the global variable for the separate data of the columns for filter button activation
var distinctColumnData = {};
// Adding the click event to the "Advanced Filter" button
$(".tabulator-header-popup-button").on('click', function(e) {
// Show the menu overlay
menuOverlay.show();
var posX = e.pageX;
var posY = e.pageY;
menuOverlay.css({
top: posY + 'px',
left: posX + 'px',
display: 'block'
});
// Get the clicked column
var columnElement = $(e.target).closest('.tabulator-col').get(0);
clickedColumn = table.getColumn(columnElement).getField();
// Removing the previous options from the list of values
$('#value-select').empty();
// Get the visible data in the selected column
var columnData = [];
var visibleRows = table.getRows("active"); // Get only the current rows
// Iteration over the visible lines
visibleRows.forEach(function(row) {
var cellValue = row.getCell(clickedColumn).getValue(); // Get the cell value for the visible row
// Adding the value to the list of distinct values
if (cellValue && columnData.indexOf(cellValue) === -1) {
columnData.push(cellValue);
// Create a checkbox for each value
var checkbox = $('<label><input type="checkbox" value="' + cellValue + '">' + cellValue + '<br>' + '</label>');
$('#value-select').append(checkbox);
}
});
// Updating the distinctColumnData variable with the distinct column data
distinctColumnData[clickedColumn] = columnData;
// Select all checkboxes in the #value-select list
$('#value-select input[type="checkbox"]').prop('checked', true);
});
// Adding the click event to the "Close menu" button
$(".close-menu-button").on('click', function() {
hideMenuOverlay();
});
// Hide or show the checkboxes based on the value entered in the input-box
function filterListValues() {
$(function() {
$('#filter-input').on('keyup', function() {
var query = this.value.toLowerCase();
$('#value-select input[type="checkbox"]').each(function(i, elem) {
if (elem.value.toLowerCase().indexOf(query) != -1) {
$(this).closest('label').show();
}else{
$(this).closest('label').hide();
}
});
});
});
}
filterListValues();
// Added icon to "Select All" button
$("#select-all-button").html('<i class="far fa-square" style="position: relative; top: -2px; left: -1px;"></i><i class="fas fa-square fa-inverse" style="position: absolute; top: 3px; left: 9px;"></i><i class="far fa-square-check" style="position: absolute; top: 3px; left: 8px;"></i>');
// Adding the click event to the "Select All" button
$("#select-all-button").on('click', function() {
// Select only value-select checkboxes that don't have a label with display: none
$('#value-select label:not([style*="display: none"]) input[type="checkbox"]').prop('checked', true);
});
// Added icon to "Clear Selection" button
$("#clear-selection-button").html('<i class="far fa-square" style="position: relative; top: -2px; left: -1px;"></i><i class="fas fa-square fa-inverse" style="position: absolute; top: 3px; left: 9px;"></i><i class="far fa-square-xmark" style="position: absolute; top: 3px; left: 8px;"></i>');
// Adding the click event to the "Clear Selection" button
$("#clear-selection-button").on('click', function() {
// Remove the filter for the current column
var columnFilter = filters.find(function(filter) {
return filter.field === clickedColumn;
});
if (columnFilter) {
var filterIndex = filters.indexOf(columnFilter);
if (filterIndex !== -1) {
filters.splice(filterIndex, 1);
}
}
// Remove the selection from all value-select checkboxes
$('#value-select input[type="checkbox"]').prop('checked', false);
});
// Update values in list, keep filter in columns already filtered
$(document).on('change', '#value-select input[type="checkbox"]', function() {
var value = $(this).val();
var columnFilter = filters.find(function(filter) {
return filter.field === clickedColumn;
});
if (columnFilter) {
if (!columnFilter.values) {
columnFilter.values = [];
}
if ($(this).is(':checked')) {
columnFilter.values.push(value);
} else {
var index = columnFilter.values.indexOf(value);
if (index !== -1) {
columnFilter.values.splice(index, 1);
}
}
} else {
columnFilter = {
field: clickedColumn,
values: []
};
if ($(this).is(':checked')) {
columnFilter.values.push(value);
filters.push(columnFilter);
}
}
});
// Added icon to "Remove Filter" button
$('#remove-filter-button').html('<i class="fas fa-filter-circle-xmark"></i>')
// Adding the click event to the "Remove Filter" button
$(document).on('click', '#remove-filter-button', function() {
// Remove the filter for the current column
$('#clear-selection-button').click();
// Click the "Filter" button to apply the remaining filters
$('#filter-button').click();
});
// Adding the click event to the "Filter" button
$(document).on('click', '#filter-button', function() {
// Close the menu
hideMenuOverlay();
// Get the current distinct data of the column
var currentColumnData = distinctColumnData[clickedColumn];
// Get the values of the selected checkboxes that don't have a label with display: none
var selectedValues = $('#value-select label').filter(function() {
return $(this).css('display') !== 'none';
}).find('input[type="checkbox"]:checked').map(function() {
return $(this).val();
}).get();
// Comparison between the current distinct data and the selected values
var isDistinctDataDifferent = JSON.stringify(currentColumnData) !== JSON.stringify(selectedValues);
// Adding/Removing the "active" class to the filtered column button
setTimeout(function() {
var targetButton = $('.tabulator-col[tabulator-field="' + clickedColumn + '"] .tabulator-header-popup-button');
if (isDistinctDataDifferent && selectedValues.length > 0) {
targetButton.addClass('active');
} else {
targetButton.removeClass('active');
}
}, 0);
// Create the filter array for Tabulator
var tabulatorFilters = filters.map(function(filter) {
return {
field: filter.field,
type: 'in',
value: filter.values
};
});
// Add the values of the selected checkboxes to the filters
if (selectedValues.length > 0) {
tabulatorFilters.push({
field: clickedColumn,
type: 'in',
value: selectedValues
});
}
// Apply filters
table.setFilter(tabulatorFilters);
});
// Close the menu when clicked out of it
$(document).on('click', function(e) {
if (!$(e.target).closest('.filter-menu').length && !$(e.target).is('#advanced-filter')) {
hideMenuOverlay();
}
});
// Function to hide the filter menu and empty the inputbox
function hideMenuOverlay() {
menuOverlay.hide();
$('#filter-input').val('');
}
} |
Here is the code that adds the operator filter. html <div class="menu-overlay">
<div class="filter-operator-window">
<button class="filter-operator-close-button">x</button>
<h3>Filtra per operatore </h3>
<select id="filter-operator-select">
<option value="=" selected>filtra numero: = uguale</option>
<option value="!=">filtra numero: != diverso</option>
<option value="<">filtra numero: < minore</option>
<option value="<=">filtra numero: <= minore-uguale</option>
<option value=">">filtra numero: > maggiore</option>
<option value=">=">filtra numero: >= maggiore-uguale</option>
<option value="between">filtra numero: da/a</option>
<option value="contains">filtra testo: contiene</option>
<option value="starts_with">filtra testo: inizia con</option>
<option value="ends_with">filtra testo: finisce con</option>
</select>
<input type="text" id="filter-value-1" placeholder="Inserisci il valore da filtrare"></input>
<input type="text" id="filter-value-2" placeholder="Inserisci il valore da filtrare"></input>
<button id="apply-filter-button">Salva</button>
</div>
<div class="filter-menu">
<button class="close-menu-button">x</button>
<button id="filter-operator">Filtra per operatore...</button>
<div id="filter-status">
<span class="filter-text"></span>
<button id="delete-filter-operator">x</button>
</div>
<input type="text" id="filter-input" placeholder="Cerca..."></input>
<button id="clear-selection-button"></button>
<button id="select-all-button"></button>
<div id="value-select">
</div>
<button id="remove-filter-button"></button>
<button id="filter-button">OK</button>
<div class="filter-menu-overlay">
</div>
</div>
</div> css #filter-operator {
background: unset;
}
#filter-operator:hover {
background-color: #ddd;
}
.filter-operator-window {
position: absolute;
bottom: 180px;
left: -25px;
width: 250px;
height: auto;
background-color: #fff;
border: 1px solid #ccc;
padding: 10px;
z-index: 1;
display: none;
}
.filter-operator-close-button {
position: relative;
float: right;
margin-top: unset !important;
border: 1px solid black;
border-radius: 4px;
cursor: pointer;
}
.filter-operator-close-button:hover {
background-color: #ddd;
}
.filter-operator-window h3 {
margin: 0 0 10px 0;
}
.filter-operator-window select,
.filter-operator-window input {
width: 100%;
margin-top: 4px;
}
.filter-operator-window button {
margin-top: 10px;
}
#filter-value-2 {
display: none;
}
#apply-filter-button {
border: 1px solid black;
border-radius: 4px;
cursor: pointer;
float: right;
background-color: #4caf50 !important;
color: white;
}
#apply-filter-button:hover {
background-color: #ddd;
}
#filter-status {
position: relative;
display: none;
}
#filter-status .filter-text {
display: inline-block;
}
#delete-filter-operator {
background-color: unset;
color: red;
border: none;
cursor: pointer;
display: none;
bottom: 1px;
position: relative;
} javascript // When you click the "Filter operator" button, the window pops up
$('#filter-operator').off('click').on('click', function() {
$('.filter-operator-window').show().addClass('active');
$('#filter-operator-select').val('=');
$('#filter-value-1').val('');
$('#filter-value-2').val('');
});
// When you click the "Filter operator close button" the window is closed
$('.filter-operator-close-button').off('click').on('click', function() {
$('.filter-operator-window').hide().removeClass('active');
});
function filterOperator() {
// Get the operator and values from the drop-down menu and input boxes
var operator = $('#filter-operator-select').val();
var value1 = $('#filter-value-1').val();
var value2 = $('#filter-value-2').val();
// Update dynamic lettering with active filter
var filterText = 'Filtro: ' + operator + ' ' + value1 + ' ' + value2;
$('#filter-status .filter-text').text(filterText);
$('#filter-status').show();
$('#delete-filter-operator').show();
// Filter the options contained in the #value-select input
$('#value-select input').each(function() {
var $label = $(this).closest('label');
// Check if the label has display: none
if ($label.css('display') === 'none') {
return; // Ignore value with display: none
}
var elementValue = $(this).val().toLowerCase();
// If the option matches the filter, show it
switch (operator) {
case '=':
if (elementValue === value1) {
$label.show();
} else {
$label.hide();
}
break;
case '!=':
if (elementValue !== value1) {
$label.show();
} else {
$label.hide();
}
break;
case '<':
if (parseInt($(this).val()) < parseInt(value1)) {
$label.show();
} else {
$label.hide();
}
break;
case '<=':
if (parseInt($(this).val()) <= parseInt(value1)) {
$label.show();
} else {
$label.hide();
}
break;
case '>':
if (parseInt($(this).val()) > parseInt(value1)) {
$label.show();
} else {
$label.hide();
}
break;
case '>=':
if (parseInt($(this).val()) >= parseInt(value1)) {
$label.show();
} else {
$label.hide();
}
break;
case 'between':
var val = parseInt($(this).val());
if (val >= parseInt(value1) && val <= parseInt(value2)) {
$label.show();
} else {
$label.hide();
}
break;
case 'contains':
if (elementValue.includes(value1)) {
$label.show();
} else {
$label.hide();
}
break;
case 'starts_with':
if (elementValue.startsWith(value1)) {
$label.show();
} else {
$label.hide();
}
break;
case 'ends_with':
if (elementValue.endsWith(value1)) {
$label.show();
} else {
$label.hide();
}
break;
default:
// Nothing needs to be done if the operator is invalid
break;
}
});
}
// When you click the "OK" button, the filter is applied to the options contained in the value-select
$('#apply-filter-button').off('click').on('click', function() {
filterOperator(); // Adding the call to the filterOperator() function
// Hide the window
$('.filter-operator-window').hide().removeClass('active');
});
// When the option in the dropdown menu is changed
$('#filter-operator-select').off('click').on('change', function() {
var selectedOperator = $(this).val();
// Show input #filter-value-2 only if the selected operator is "between"
if (selectedOperator === 'between') {
$('#filter-value-2').show();
} else {
$('#filter-value-2').hide();
}
});
// When you click the "x" button to delete the filter
$('#delete-filter-operator').off('click').on('click', function() {
// Get the current value into the input of the #filter-input
var filterInputValue = $('#filter-input').val().toLowerCase();
// Show all hidden values
$('#value-select input').closest('label').show();
// Hide the filter text and the "x" button
$('#filter-status').hide();
$('#delete-filter-operator').hide();
// Reset the operator and values to their default values
$('#filter-operator-select').val('=');
$('#filter-value-1').val('');
$('#filter-value-2').val('');
// Reapply the input filter if there is an inserted value
if (filterInputValue !== '') {
filterListValues(filterInputValue);
}
});
// Function to filter the input values based on the value entered in the input-box
function filterListValues(query) {
$('#value-select input[type="checkbox"]').each(function(i, elem) {
var $label = $(this).closest('label');
if (elem.value.toLowerCase().indexOf(query) !== -1) {
$label.show();
} else {
$label.hide();
}
});
}
// When the value in the input-box is changed
$('#filter-input').off('keyup').on('keyup', function() {
var query = this.value.toLowerCase();
filterListValues(query);
// Get the values of #filter-value-1 and #filter-value-2
var value1 = $('#filter-value-1').val();
var value2 = $('#filter-value-2').val();
// Apply filterOperator() only if at least one of the two values has been set
if (value1 !== '' || value2 !== '') {
filterOperator();
}
}); |
Tabulator already provides an example of how to achieve this, checkout the header menu here: Cheers Oli |
This is the column filter of handsontable.
Is there something similar for tabulator?
Documentation here: https://handsontable.com/docs/javascript-data-grid/column-filter/
Many thanks for your work.
The text was updated successfully, but these errors were encountered: