feat(filter): Filter now supports complex queries for Number columns
More advanced filter support for Number columns For e.g >5000 filters rows with the cell value greater than 5000 <30 filters rows with cell value less than 30 20:340 filters rows with cell value in the range of 20 and 340 You can also provide a custom filter function by providing a `filterRows` function in the options during initialization.
This commit is contained in:
parent
ae6415c950
commit
cdb276abfd
@ -99,6 +99,11 @@
|
|||||||
data,
|
data,
|
||||||
inlineFilters: true,
|
inlineFilters: true,
|
||||||
dynamicRowHeight: true,
|
dynamicRowHeight: true,
|
||||||
|
// filterRows(keyword, cells, colIndex) {
|
||||||
|
// return cells
|
||||||
|
// .filter(cell => cell.content.includes(keyword))
|
||||||
|
// .map(cell => cell.rowIndex);
|
||||||
|
// },
|
||||||
getEditor(colIndex, rowIndex, value, parent) {
|
getEditor(colIndex, rowIndex, value, parent) {
|
||||||
// editing obj only for date field
|
// editing obj only for date field
|
||||||
if (colIndex != 6) return;
|
if (colIndex != 6) return;
|
||||||
|
|||||||
@ -13,6 +13,7 @@ export default class CellManager {
|
|||||||
'wrapper',
|
'wrapper',
|
||||||
'options',
|
'options',
|
||||||
'style',
|
'style',
|
||||||
|
'header',
|
||||||
'bodyScrollable',
|
'bodyScrollable',
|
||||||
'columnmanager',
|
'columnmanager',
|
||||||
'rowmanager',
|
'rowmanager',
|
||||||
@ -121,6 +122,10 @@ export default class CellManager {
|
|||||||
this.activateFilter(colIndex);
|
this.activateFilter(colIndex);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$.on(this.header, 'focusin', '.dt-filter', () => {
|
||||||
|
this.unfocusCell(this.$focusedCell);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,6 +251,19 @@ export default class CellManager {
|
|||||||
this.highlightRowColumnHeader($cell);
|
this.highlightRowColumnHeader($cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unfocusCell($cell) {
|
||||||
|
if (!$cell) return;
|
||||||
|
|
||||||
|
// remove cell border
|
||||||
|
$cell.classList.remove('dt-cell--focus');
|
||||||
|
this.$focusedCell = null;
|
||||||
|
|
||||||
|
// reset header background
|
||||||
|
if (this.lastHeaders) {
|
||||||
|
this.lastHeaders.forEach(header => header.classList.remove('dt-cell--highlight'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
highlightRowColumnHeader($cell) {
|
highlightRowColumnHeader($cell) {
|
||||||
const {
|
const {
|
||||||
colIndex,
|
colIndex,
|
||||||
|
|||||||
@ -269,24 +269,26 @@ export default class ColumnManager {
|
|||||||
bindFilter() {
|
bindFilter() {
|
||||||
if (!this.options.inlineFilters) return;
|
if (!this.options.inlineFilters) return;
|
||||||
const handler = e => {
|
const handler = e => {
|
||||||
const $filterCell = $.closest('.dt-cell', e.target);
|
this.$filterCell = $.closest('.dt-cell', e.target);
|
||||||
const {
|
const { colIndex } = $.data(this.$filterCell);
|
||||||
colIndex
|
|
||||||
} = $.data($filterCell);
|
|
||||||
const keyword = e.target.value;
|
const keyword = e.target.value;
|
||||||
|
|
||||||
this.datamanager.filterRows(keyword, colIndex)
|
this.applyFilter(keyword, colIndex);
|
||||||
.then(({
|
|
||||||
rowsToHide,
|
|
||||||
rowsToShow
|
|
||||||
}) => {
|
|
||||||
this.rowmanager.hideRows(rowsToHide);
|
|
||||||
this.rowmanager.showRows(rowsToShow);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
$.on(this.header, 'keydown', '.dt-filter', debounce(handler, 300));
|
$.on(this.header, 'keydown', '.dt-filter', debounce(handler, 300));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applyFilter(keyword, colIndex) {
|
||||||
|
this.datamanager.filterRows(keyword, colIndex)
|
||||||
|
.then(({
|
||||||
|
rowsToHide,
|
||||||
|
rowsToShow
|
||||||
|
}) => {
|
||||||
|
this.rowmanager.hideRows(rowsToHide);
|
||||||
|
this.rowmanager.showRows(rowsToShow);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
applyDefaultSortOrder() {
|
applyDefaultSortOrder() {
|
||||||
// sort rows if any 1 column has a default sortOrder set
|
// sort rows if any 1 column has a default sortOrder set
|
||||||
const columnsToSort = this.getColumns().filter(col => col.sortOrder !== 'none');
|
const columnsToSort = this.getColumns().filter(col => col.sortOrder !== 'none');
|
||||||
|
|||||||
@ -11,7 +11,6 @@ export default class DataManager {
|
|||||||
this.sortRows = nextTick(this.sortRows, this);
|
this.sortRows = nextTick(this.sortRows, this);
|
||||||
this.switchColumn = nextTick(this.switchColumn, this);
|
this.switchColumn = nextTick(this.switchColumn, this);
|
||||||
this.removeColumn = nextTick(this.removeColumn, this);
|
this.removeColumn = nextTick(this.removeColumn, this);
|
||||||
this.filterRows = nextTick(this.filterRows, this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init(data, columns) {
|
init(data, columns) {
|
||||||
@ -423,31 +422,36 @@ export default class DataManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
filterRows(keyword, colIndex) {
|
filterRows(keyword, colIndex) {
|
||||||
let rowsToHide = [];
|
|
||||||
let rowsToShow = [];
|
|
||||||
const cells = this.rows.map(row => row[colIndex]);
|
const cells = this.rows.map(row => row[colIndex]);
|
||||||
|
let result = this.options.filterRows(keyword, cells, colIndex);
|
||||||
|
|
||||||
cells.forEach(cell => {
|
if (!result) {
|
||||||
const hay = String(cell.content || '').toLowerCase();
|
result = this.getAllRowIndices();
|
||||||
const needle = (keyword || '').toLowerCase();
|
}
|
||||||
|
|
||||||
if (!needle || hay.includes(needle)) {
|
if (!result.then) {
|
||||||
rowsToShow.push(cell.rowIndex);
|
result = Promise.resolve(result);
|
||||||
} else {
|
}
|
||||||
rowsToHide.push(cell.rowIndex);
|
|
||||||
}
|
return result.then(rowsToShow => {
|
||||||
|
this._filteredRows = rowsToShow;
|
||||||
|
|
||||||
|
const rowsToHide = this.getAllRowIndices()
|
||||||
|
.filter(index => !rowsToShow.includes(index));
|
||||||
|
|
||||||
|
return {
|
||||||
|
rowsToHide,
|
||||||
|
rowsToShow
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
this._filteredRows = rowsToShow;
|
|
||||||
|
|
||||||
return {
|
|
||||||
rowsToHide,
|
|
||||||
rowsToShow
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getFilteredRowIndices() {
|
getFilteredRowIndices() {
|
||||||
return this._filteredRows || this.rows.map(row => row.meta.rowIndex);
|
return this._filteredRows || this.getAllRowIndices();
|
||||||
|
}
|
||||||
|
|
||||||
|
getAllRowIndices() {
|
||||||
|
return this.rows.map(row => row.meta.rowIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
getRowCount() {
|
getRowCount() {
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import filterRows from './filterRows';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
columns: [],
|
columns: [],
|
||||||
data: [],
|
data: [],
|
||||||
@ -40,6 +42,7 @@ export default {
|
|||||||
desc: '↓',
|
desc: '↓',
|
||||||
none: ''
|
none: ''
|
||||||
},
|
},
|
||||||
|
filterRows: filterRows,
|
||||||
freezeMessage: '',
|
freezeMessage: '',
|
||||||
getEditor: null,
|
getEditor: null,
|
||||||
serialNoColumn: true,
|
serialNoColumn: true,
|
||||||
|
|||||||
93
src/filterRows.js
Normal file
93
src/filterRows.js
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
import { isNumber } from './utils';
|
||||||
|
|
||||||
|
export default function filterRows(keyword, cells, colIndex) {
|
||||||
|
let filter = guessFilter(keyword);
|
||||||
|
let filterMethod = getFilterMethod(filter);
|
||||||
|
|
||||||
|
if (filterMethod) {
|
||||||
|
return filterMethod(filter.text, cells);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cells.map(cell => cell.rowIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
function getFilterMethod(filter) {
|
||||||
|
let filterMethodMap = {
|
||||||
|
contains(keyword, cells) {
|
||||||
|
return cells
|
||||||
|
.filter(cell => {
|
||||||
|
const hay = String(cell.content || '').toLowerCase();
|
||||||
|
const needle = (keyword || '').toLowerCase();
|
||||||
|
return !needle || hay.includes(needle);
|
||||||
|
})
|
||||||
|
.map(cell => cell.rowIndex);
|
||||||
|
},
|
||||||
|
|
||||||
|
greaterThan(keyword, cells) {
|
||||||
|
return cells
|
||||||
|
.filter(cell => {
|
||||||
|
const value = Number(cell.content);
|
||||||
|
return value > keyword;
|
||||||
|
})
|
||||||
|
.map(cell => cell.rowIndex);
|
||||||
|
},
|
||||||
|
|
||||||
|
lessThan(keyword, cells) {
|
||||||
|
return cells
|
||||||
|
.filter(cell => {
|
||||||
|
const value = Number(cell.content);
|
||||||
|
return value < keyword;
|
||||||
|
})
|
||||||
|
.map(cell => cell.rowIndex);
|
||||||
|
},
|
||||||
|
|
||||||
|
range(rangeValues, cells) {
|
||||||
|
return cells
|
||||||
|
.filter(cell => {
|
||||||
|
const value = Number(cell.content);
|
||||||
|
return value >= rangeValues[0] && value <= rangeValues[1];
|
||||||
|
})
|
||||||
|
.map(cell => cell.rowIndex);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return filterMethodMap[filter.type];
|
||||||
|
}
|
||||||
|
|
||||||
|
function guessFilter(keyword) {
|
||||||
|
if (keyword.length === 1) return {};
|
||||||
|
|
||||||
|
if (keyword.startsWith('>')) {
|
||||||
|
if (isNumber(keyword.slice(1))) {
|
||||||
|
return {
|
||||||
|
type: 'greaterThan',
|
||||||
|
text: Number(keyword.slice(1).trim())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
keyword = keyword.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyword.startsWith('<')) {
|
||||||
|
if (isNumber(keyword.slice(1))) {
|
||||||
|
return {
|
||||||
|
type: 'lessThan',
|
||||||
|
text: Number(keyword.slice(1).trim())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
keyword = keyword.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyword.split(':').length === 2 && keyword.split(':').every(isNumber)) {
|
||||||
|
return {
|
||||||
|
type: 'range',
|
||||||
|
text: keyword.split(':').map(v => v.trim()).map(Number)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'contains',
|
||||||
|
text: keyword.toLowerCase()
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -277,7 +277,7 @@ export default class RowManager {
|
|||||||
|
|
||||||
getFilterInput(props) {
|
getFilterInput(props) {
|
||||||
const dataAttr = makeDataAttributeString(props);
|
const dataAttr = makeDataAttributeString(props);
|
||||||
return `<input class="dt-filter dt-input" type="text" ${dataAttr} />`;
|
return `<input class="dt-filter dt-input" type="text" ${dataAttr} tabindex="1" />`;
|
||||||
}
|
}
|
||||||
|
|
||||||
selector(rowIndex) {
|
selector(rowIndex) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user