Skip to content

Commit

Permalink
Merge pull request #1317 from gregnb/confirmFiltersV3
Browse files Browse the repository at this point in the history
Added confirmFilters option (deprecates serverSideFilterList)
  • Loading branch information
patorjk authored Jun 8, 2020
2 parents afe8782 + 70059e8 commit 8929a73
Show file tree
Hide file tree
Showing 12 changed files with 300 additions and 158 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,15 @@ The component accepts the following props:
|Name|Type|Default|Description
|:--:|:-----|:--|:-----|
|**`caseSensitive `**|boolean|false|Enable/disable case sensitivity for search.
|**`confirmFilters`**|boolean|false|Works in conjunction with the **customFilterDialogFooter** option and makes it so filters have to be confirmed before being applied to the table. When this option is true, the customFilterDialogFooter callback will receive an applyFilters function which, when called, will apply the filters to the table. [Example](https://github.com/gregnb/mui-datatables/blob/master/examples/serverside-filters/index.js)
|**`count`**|number||User provided override for total number of rows.
|**`customFilterDialogFooter `**|function||Add a custom footer to the filter dialog. `customFilterDialogFooter(filterList: array) => React Component`
|**`customFilterDialogFooter `**|function||Add a custom footer to the filter dialog. `customFilterDialogFooter(curentFilterList: array, applyFilters: function) => React Component`
|**`customFooter`**|function||Render a custom table footer. `function(count, page, rowsPerPage, changeRowsPerPage, changePage, `[`textLabels: object`](https://github.com/gregnb/mui-datatables/blob/master/src/textLabels.js)`) => string`|` React Component` [Example](https://github.com/gregnb/mui-datatables/blob/master/examples/customize-footer/index.js)
|**`customTableBodyFooterRender`**|function||Render a footer under the table body but above the table's standard footer. This is useful for creating footers for individual columns. [Example](https://github.com/gregnb/mui-datatables/blob/master/examples/customize-footer/index.js)
|**`customRowRender `**|function||Override default row rendering with custom function. `customRowRender(data, dataIndex, rowIndex) => React Component`
|**`customSearch `**|function||Override default search with custom function. `customSearch(searchQuery: string, currentRow: array, columns: array) => boolean`
|**`customSearchRender `**|function||Render a custom table search. `customSearchRender(searchText: string, handleSearch, hideSearch, options) => React Component`
|**`customFilterDialogFooter `**|function||Add a custom footer to the filter dialog. `customFilterDialogFooter(filterList: array) => React Component`
|**`customFilterDialogFooter `**|function||Add a custom footer to the filter dialog. `customFilterDialogFooter(curentFilterList: array, applyFilters: function) => React Component`
|**`elevation`**|number|4|Shadow depth applied to Paper component
|**`caseSensitive `**|boolean|false|Enable/disable case sensitivity for search
|**`responsive`**|string|'stacked'|Enable/disable responsive table views. Options: <p><ul><li>"vertical" (default value): In smaller views the table cells will collapse such that the heading is to the left of the cell value.</li><li>"standard": Table will stay in the standard mode but make small changes to better fit the allocated space.<li>"simple": On very small devices the table rows will collapse into simple display.</li></ul></p>[Example](https://github.com/gregnb/mui-datatables/blob/master/examples/simple/index.js)
Expand Down Expand Up @@ -195,7 +196,8 @@ The component accepts the following props:
|**`onChangeRowsPerPage`**|function||Callback function that triggers when the number of rows per page has changed. `function(numberOfRows: number) => void`
|**`onColumnSortChange`**|function||Callback function that triggers when a column has been sorted. `function(changedColumn: string, direction: string) => void`
|**`onDownload`**|function||A callback function that triggers when the user downloads the CSV file. In the callback, you can control what is written to the CSV file. This method can be used to add the Excel specific BOM character (see this [example](https://github.com/gregnb/mui-datatables/pull/722#issuecomment-526346440)). `function(buildHead: (columns) => string, buildBody: (data) => string, columns, data) => string`. Return `false` to cancel download of file.
|**`onFilterChange`**|function||Callback function that triggers when filters have changed. `function(changedColumn: string, filterList: array, type: enum('checkbox', 'dropdown', 'multiselect', 'textField', 'custom', 'chip', 'reset')) => void`
|**`onFilterChange`**|function||Callback function that triggers when filters have changed. `function(changedColumn: string, filterList: array, type: enum('checkbox', 'dropdown', 'multiselect', 'textField', 'custom', 'chip', 'reset'), changedColumnIndex, displayData) => void`
|**`onFilterConfirm`**|function||Callback function that is triggered when a user presses the "confirm" button on the filter popover. This occurs only if you've set **confirmFilters** option to true. `function(filterList: array) => void` [Example](https://github.com/gregnb/mui-datatables/blob/master/examples/serverside-filters/index.js)
|**`onFilterDialogClose`**|function||Callback function that triggers when the filter dialog closes. `function() => void`
|**`onFilterDialogOpen`**|function||Callback function that triggers when the filter dialog opens. `function() => void`
|**`onRowClick`**|function||Callback function that triggers when a row is clicked. `function(rowData: string[], rowMeta: { dataIndex: number, rowIndex: number }) => void`
Expand Down
1 change: 1 addition & 0 deletions examples/customize-filter/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class Example extends React.Component {
renderValue: v => v ? v.replace(/^(\w).* (.*)$/, '$1. $2') : ''
},
display: 'excluded',
filterType: 'textField'
},
},
{
Expand Down
15 changes: 13 additions & 2 deletions examples/large-data-set/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from "react";
import ReactDOM from "react-dom";
import MUIDataTable from "../../src/";
import { debounceSearchRender } from "../../src/";
import { Button } from '@material-ui/core';

class Example extends React.Component {

Expand Down Expand Up @@ -61,8 +62,6 @@ class Example extends React.Component {
options: {
filter: true,
customBodyRender: (val, tableMeta) => {
//console.log(val);
//console.dir(tableMeta);
return val;
}
}
Expand Down Expand Up @@ -124,6 +123,18 @@ class Example extends React.Component {
responsive: 'vertical',
tableBodyHeight:'500px',
customSearchRender: debounceSearchRender(500),

// These next two options allow you to make it so filters need to be confirmed.
confirmFilters: true,

// Calling the applyNewFilters parameter applies the selected filters to the table
customFilterDialogFooter: (currentFilterList, applyNewFilters) => {
return (
<div style={{ marginTop: '40px' }}>
<Button variant="contained" onClick={applyNewFilters}>Apply Filters</Button>
</div>
);
}
};

return (
Expand Down
177 changes: 81 additions & 96 deletions examples/serverside-filters/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,112 +3,90 @@ import React from 'react';
import ReactDOM from 'react-dom';
import MUIDataTable from '../../src';

const theData = [
['Gabby George', 'Business Analyst', 'Minneapolis', 30, '$100,000'],
['Aiden Lloyd', 'Business Consultant', 'Dallas', 55, '$200,000'],
['Jaden Collins', 'Attorney', 'Santa Ana', 27, '$500,000'],
['Franky Rees', 'Business Analyst', 'St. Petersburg', 22, '$50,000'],
['Aaren Rose', 'Business Consultant', 'Toledo', 28, '$75,000'],
['Blake Duncan', 'Business Management Analyst', 'San Diego', 65, '$94,000'],
['Frankie Parry', 'Agency Legal Counsel', 'Jacksonville', 71, '$210,000'],
['Lane Wilson', 'Commercial Specialist', 'Chicago', 19, '$65,000'],
['Robin Duncan', 'Business Analyst', 'Los Angeles', 20, '$77,000'],
['Mel Brooks', 'Business Consultant', 'Oklahoma City', 37, '$135,000'],
['Harper White', 'Attorney', 'Pittsburgh', 52, '$420,000'],
['Kris Humphrey', 'Agency Legal Counsel', 'Laredo', 30, '$150,000'],
['Frankie Long', 'Industrial Analyst', 'Austin', 31, '$170,000'],
['Brynn Robbins', 'Business Analyst', 'Norfolk', 22, '$90,000'],
['Justice Mann', 'Business Consultant', 'Chicago', 24, '$133,000'],
['Addison Navarro', 'Business Management Analyst', 'New York', 50, '$295,000'],
['Jesse Welch', 'Agency Legal Counsel', 'Seattle', 28, '$200,000'],
['Eli Mejia', 'Commercial Specialist', 'Long Beach', 65, '$400,000'],
['Gene Leblanc', 'Industrial Analyst', 'Hartford', 34, '$110,000'],
['Danny Leon', 'Computer Scientist', 'Newark', 60, '$220,000'],
['Lane Lee', 'Corporate Counselor', 'Cincinnati', 52, '$180,000'],
['Jesse Hall', 'Business Analyst', 'Baltimore', 44, '$99,000'],
['Danni Hudson', 'Agency Legal Counsel', 'Tampa', 37, '$90,000'],
['Terry Macdonald', 'Commercial Specialist', 'Miami', 39, '$140,000'],
['Justice Mccarthy', 'Attorney', 'Tucson', 26, '$330,000'],
['Silver Carey', 'Computer Scientist', 'Memphis', 47, '$250,000'],
['Franky Miles', 'Industrial Analyst', 'Buffalo', 49, '$190,000'],
['Glen Nixon', 'Corporate Counselor', 'Arlington', 44, '$80,000'],
['Gabby Strickland', 'Business Process Consultant', 'Scottsdale', 26, '$45,000'],
['Mason Ray', 'Computer Scientist', 'San Francisco', 39, '$142,000'],
];

class Example extends React.Component {
state = {
serverSideFilterList: [],
filters: [[], [], [], [], []],
isLoading: false,
data: [
['Gabby George', 'Business Analyst', 'Minneapolis', 30, '$100,000'],
['Aiden Lloyd', 'Business Consultant', 'Dallas', 55, '$200,000'],
['Jaden Collins', 'Attorney', 'Santa Ana', 27, '$500,000'],
['Franky Rees', 'Business Analyst', 'St. Petersburg', 22, '$50,000'],
['Aaren Rose', 'Business Consultant', 'Toledo', 28, '$75,000'],
['Blake Duncan', 'Business Management Analyst', 'San Diego', 65, '$94,000'],
['Frankie Parry', 'Agency Legal Counsel', 'Jacksonville', 71, '$210,000'],
['Lane Wilson', 'Commercial Specialist', 'Chicago', 19, '$65,000'],
['Robin Duncan', 'Business Analyst', 'Los Angeles', 20, '$77,000'],
['Mel Brooks', 'Business Consultant', 'Oklahoma City', 37, '$135,000'],
['Harper White', 'Attorney', 'Pittsburgh', 52, '$420,000'],
['Kris Humphrey', 'Agency Legal Counsel', 'Laredo', 30, '$150,000'],
['Frankie Long', 'Industrial Analyst', 'Austin', 31, '$170,000'],
['Brynn Robbins', 'Business Analyst', 'Norfolk', 22, '$90,000'],
['Justice Mann', 'Business Consultant', 'Chicago', 24, '$133,000'],
['Addison Navarro', 'Business Management Analyst', 'New York', 50, '$295,000'],
['Jesse Welch', 'Agency Legal Counsel', 'Seattle', 28, '$200,000'],
['Eli Mejia', 'Commercial Specialist', 'Long Beach', 65, '$400,000'],
['Gene Leblanc', 'Industrial Analyst', 'Hartford', 34, '$110,000'],
['Danny Leon', 'Computer Scientist', 'Newark', 60, '$220,000'],
['Lane Lee', 'Corporate Counselor', 'Cincinnati', 52, '$180,000'],
['Jesse Hall', 'Business Analyst', 'Baltimore', 44, '$99,000'],
['Danni Hudson', 'Agency Legal Counsel', 'Tampa', 37, '$90,000'],
['Terry Macdonald', 'Commercial Specialist', 'Miami', 39, '$140,000'],
['Justice Mccarthy', 'Attorney', 'Tucson', 26, '$330,000'],
['Silver Carey', 'Computer Scientist', 'Memphis', 47, '$250,000'],
['Franky Miles', 'Industrial Analyst', 'Buffalo', 49, '$190,000'],
['Glen Nixon', 'Corporate Counselor', 'Arlington', 44, '$80,000'],
['Gabby Strickland', 'Business Process Consultant', 'Scottsdale', 26, '$45,000'],
['Mason Ray', 'Computer Scientist', 'San Francisco', 39, '$142,000'],
]
data: theData
};

// mock async function
xhrRequest = (url, filterList) => {
return new Promise(resolve => {
window.setTimeout(
() => {
const data = [
['Gabby George', 'Business Analyst', 'Minneapolis', 30, '$100,000'],
['Aiden Lloyd', 'Business Consultant', 'Dallas', 55, '$200,000'],
['Jaden Collins', 'Attorney', 'Santa Ana', 27, '$500,000'],
['Franky Rees', 'Business Analyst', 'St. Petersburg', 22, '$50,000'],
['Aaren Rose', 'Business Consultant', 'Toledo', 28, '$75,000'],
['Blake Duncan', 'Business Management Analyst', 'San Diego', 65, '$94,000'],
['Frankie Parry', 'Agency Legal Counsel', 'Jacksonville', 71, '$210,000'],
['Lane Wilson', 'Commercial Specialist', 'Chicago', 19, '$65,000'],
['Robin Duncan', 'Business Analyst', 'Los Angeles', 20, '$77,000'],
['Mel Brooks', 'Business Consultant', 'Oklahoma City', 37, '$135,000'],
['Harper White', 'Attorney', 'Pittsburgh', 52, '$420,000'],
['Kris Humphrey', 'Agency Legal Counsel', 'Laredo', 30, '$150,000'],
['Frankie Long', 'Industrial Analyst', 'Austin', 31, '$170,000'],
['Brynn Robbins', 'Business Analyst', 'Norfolk', 22, '$90,000'],
['Justice Mann', 'Business Consultant', 'Chicago', 24, '$133,000'],
['Addison Navarro', 'Business Management Analyst', 'New York', 50, '$295,000'],
['Jesse Welch', 'Agency Legal Counsel', 'Seattle', 28, '$200,000'],
['Eli Mejia', 'Commercial Specialist', 'Long Beach', 65, '$400,000'],
['Gene Leblanc', 'Industrial Analyst', 'Hartford', 34, '$110,000'],
['Danny Leon', 'Computer Scientist', 'Newark', 60, '$220,000'],
['Lane Lee', 'Corporate Counselor', 'Cincinnati', 52, '$180,000'],
['Jesse Hall', 'Business Analyst', 'Baltimore', 44, '$99,000'],
['Danni Hudson', 'Agency Legal Counsel', 'Tampa', 37, '$90,000'],
['Terry Macdonald', 'Commercial Specialist', 'Miami', 39, '$140,000'],
['Justice Mccarthy', 'Attorney', 'Tucson', 26, '$330,000'],
['Silver Carey', 'Computer Scientist', 'Memphis', 47, '$250,000'],
['Franky Miles', 'Industrial Analyst', 'Buffalo', 49, '$190,000'],
['Glen Nixon', 'Corporate Counselor', 'Arlington', 44, '$80,000'],
['Gabby Strickland', 'Business Process Consultant', 'Scottsdale', 26, '$45,000'],
['Mason Ray', 'Computer Scientist', 'San Francisco', 39, '$142,000'],
];
const newData = [
['Lane Wilson', 'Commercial Specialist', 'Chicago', 19, '$65,000'],
['Justice Mann', 'Business Consultant', 'Chicago', 24, '$133,000']
];
const data = theData;

if (
!filterList[0].length
&& !filterList[1].length
&& !filterList[2].length
&& !filterList[3].length
&& !filterList[4].length
filterList.reduce( (accu, cur) => accu + cur.length, 0) === 0
) {
resolve({ data });
} else {
resolve({ data: newData });

/*
This code simulates filtering that would occur on the back-end
*/
var filteredData = data.filter(row => {
var ret = true;

for (var ii = 0; ii <= 4; ii++) {
if (filterList[ii] && filterList[ii].length) {
ret = ret && filterList[ii].filter(ff => {
return row[ii] == ff;
}).length > 0;
}
}
return ret;
});

resolve({ data: filteredData });
}
},
2000
);
});
}

handleFilterSubmit = filterList => () => {
console.log('Submitting filters: ', filterList);
handleFilterSubmit = applyFilters => {
let filterList = applyFilters();

this.setState({ isLoading: true, filters: filterList });
this.setState({ isLoading: true });

// fake async request
this.xhrRequest(`/myApiServer?filters=${filterList}`, filterList).then(res => {
this.setState({ isLoading: false, data: res.data, serverSideFilterList: filterList });
this.setState({ isLoading: false, data: res.data });
});
};

Expand All @@ -118,46 +96,60 @@ class Example extends React.Component {
name: 'Name',
options: {
filter: true,
filterList: this.state.filters[0],
},
},
{
label: 'Title',
name: 'Title',
options: {
filter: true,
filterList: this.state.filters[1],
},
},
{
name: 'Location',
options: {
filter: true,
filterList: this.state.filters[2],
},
},
{
name: 'Age',
options: {
filter: true,
filterList: this.state.filters[3],
},
},
{
name: 'Salary',
options: {
filter: true,
filterList: this.state.filters[4],
},
},
];

const options = {
filter: true,
serverSideFilterList: this.state.serverSideFilterList,
filter: true, // show the filter icon in the toolbar (true by default)
filterType: 'dropdown',
responsive: 'standard',
serverSide: true,

// makes it so filters have to be "confirmed" before being applied to the
// table's internal filterList
confirmFilters: true,

// Calling the applyNewFilters parameter applies the selected filters to the table
customFilterDialogFooter: (currentFilterList, applyNewFilters) => {
return (
<div style={{ marginTop: '40px' }}>
<Button variant="contained" onClick={() => this.handleFilterSubmit(applyNewFilters)}>Apply Filters</Button>
</div>
);
},

// callback that gets executed when filters are confirmed
onFilterConfirm: (filterList) => {
console.log('onFilterConfirm');
console.dir(filterList);
},

onFilterDialogOpen: () => {
console.log('filter dialog opened');
},
Expand All @@ -166,18 +158,11 @@ class Example extends React.Component {
},
onFilterChange: (column, filterList, type) => {
if (type === 'chip') {
var newFilters = () => (filterList);
console.log('updating filters via chip');
this.handleFilterSubmit(filterList)();
this.handleFilterSubmit(newFilters);
}
},
customFilterDialogFooter: filterList => {
return (
<div style={{ marginTop: '40px' }}>
<Button variant="contained" onClick={this.handleFilterSubmit(filterList)}>Apply Filters*</Button>
<p><em>*(Simulates selecting "Chicago" from "Location")</em></p>
</div>
);
}
};

return (
Expand Down
1 change: 0 additions & 1 deletion examples/simple/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, {useState} from "react";
import ReactDOM from "react-dom";
import MUIDataTable from "../../src/";

import InputLabel from '@material-ui/core/InputLabel';
import MenuItem from '@material-ui/core/MenuItem';
import FormHelperText from '@material-ui/core/FormHelperText';
Expand Down
Loading

0 comments on commit 8929a73

Please sign in to comment.