Repository: gregnb/mui-datatables (js)

Issue:
Make availability to hide column from MUIDataTableViewCol, but show in table
## Expected Behavior
It will be a good idea to hide column from View Columns menu, and always show it in table itself.

## Current Behavior
We can't provide an option for columns property not to show column in View Columns menu.

Pull request:
Feature/column filter options
When merged should close #289 #125 #227 

Patch:
diff --git a/README.md b/README.md
index 929a3b1..2e1fee2 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
 [![dependencies Status](https://david-dm.org/gregnb/mui-datatables/status.svg)](https://david-dm.org/gregnb/mui-datatables)
 [![npm version](https://badge.fury.io/js/mui-datatables.svg)](https://badge.fury.io/js/mui-datatables)
 
-MUI-Datatables is a data tables component built on [Material-UI V1](https://www.material-ui-next.com).  It comes with features like filtering, resizable + view/hide columns, search, export to CSV download, printing, selectable rows, expandable rows, pagination, and sorting. On top of the ability to customize styling on most views, there are two responsive modes "stacked" and "scroll" for mobile/tablet devices.
+MUI-Datatables is a data tables component built on [Material-UI](https://www.material-ui.com).  It comes with features like filtering, resizable + view/hide columns, search, export to CSV download, printing, selectable rows, expandable rows, pagination, and sorting. On top of the ability to customize styling on most views, there are two responsive modes "stacked" and "scroll" for mobile/tablet devices.
 
 <div align="center">
 	<img src="https://user-images.githubusercontent.com/19170080/38026128-eac9d506-3258-11e8-92a7-b0d06e5faa82.gif" />
@@ -130,7 +130,6 @@ The component accepts the following props:
 |**`page`**|number||User provided starting page for pagination
 |**`count`**|number||User provided override for total number of rows
 |**`serverSide`**|boolean|false|Enable remote data source
-|**`filterList`**|array||User provided filter list
 |**`rowsSelected`**|array||User provided selected rows
 |**`filterType `**|string|'dropdown'|Choice of filtering view. Options are "checkbox", "dropdown", or "multiselect"
 |**`textLabels `**|object||User provided labels to localize text
@@ -201,10 +200,12 @@ const columns = [
 |Name|Type|Default|Description
 |:--:|:-----|:--|:-----|
 |**`display`**|string|'true'|Display column in table. `enum('true', 'false', 'excluded')`
+|**`filterList`**|array||Filter value list [Example](https://github.com/gregnb/mui-datatables/blob/master/examples/column-filters/index.js)
+|**`filterOptons`**|array||Filter options [Example](https://github.com/gregnb/mui-datatables/blob/master/examples/column-filters/index.js)
 |**`filter`**|boolean|true|Display column in filter list
 |**`sort`**|boolean|true|Enable/disable sorting on column
 |**`download`**|boolean|true|Display column in CSV download file
-|**`hint`**|string|`undefined`Display hint icon with string as tooltip on hover.
+|**`hint`**|string||Display hint icon with string as tooltip on hover.
 |**`customHeadRender`**|function||Function that returns a string or React component. Used as display for column header. `function(value, tableMeta, updateValue) => string`&#124;
 |**`customBodyRender`**|function||Function that returns a string or React component. Used as display data within all table cells of a given column. `function(value, tableMeta, updateValue) => string`&#124;` React Component` [Example](https://github.com/gregnb/mui-datatables/blob/master/examples/component/index.js)
 |**`setCellProps`**|function||Is called for each cell and allows to return custom props for this cell based on its data. `function(cellValue: string, rowIndex: number, columnIndex: number) => string`
diff --git a/examples/column-filters/index.js b/examples/column-filters/index.js
new file mode 100644
index 0000000..7551d92
--- /dev/null
+++ b/examples/column-filters/index.js
@@ -0,0 +1,93 @@
+import React from "react";
+import ReactDOM from "react-dom";
+import MUIDataTable from "../../src/";
+
+class Example extends React.Component {
+
+  render() {
+
+    const columns = [
+      {
+        name: "Name",
+        options: {
+          filter: true,
+          filterList: ['Franky Miles'],
+          filterOptions: ['a', 'b', 'c', 'Business Analyst']
+        }
+      },      
+      {
+        name: "Title",
+        options: {
+          filter: true,
+        }
+      },
+      {
+        name: "Location",
+        options: {
+          filter: false,
+        }
+      },
+      {
+        name: "Age",
+        options: {
+          filter: true,
+        }
+      },
+      {
+        name: "Salary",
+        options: {
+          filter: true,
+          sort: false
+        }
+      }      
+    ];
+    const data = [
+      ["Gabby George", "Business Analyst", "Minneapolis", 30, 100000],
+      ["Business Analyst", "Business Consultant", "Dallas",  55, 200000],
+      ["Jaden Collins", "Attorney", "Santa Ana", 27, 500000],
+      ["Franky Rees", "Business Analyst", "St. Petersburg", 22, 50000],
+      ["Aaren Rose", "Business Consultant", "Toledo", 28, 75000],
+      ["Blake Duncan", "Business Management Analyst", "San Diego", 65, 94000],
+      ["Frankie Parry", "Agency Legal Counsel", "Jacksonville", 71, 210000],
+      ["Lane Wilson", "Commercial Specialist", "Omaha", 19, 65000],
+      ["Robin Duncan", "Business Analyst", "Los Angeles", 20, 77000],
+      ["Mel Brooks", "Business Consultant", "Oklahoma City", 37, 135000],
+      ["Harper White", "Attorney", "Pittsburgh", 52, 420000],
+      ["Kris Humphrey", "Agency Legal Counsel", "Laredo", 30, 150000],
+      ["Frankie Long", "Industrial Analyst", "Austin", 31, 170000],
+      ["Brynn Robbins", "Business Analyst", "Norfolk", 22, 90000],
+      ["Justice Mann", "Business Consultant", "Chicago", 24, 133000],
+      ["Addison Navarro", "Business Management Analyst", "New York", 50, 295000],
+      ["Jesse Welch", "Agency Legal Counsel", "Seattle", 28, 200000],
+      ["Eli Mejia", "Commercial Specialist", "Long Beach", 65, 400000],
+      ["Gene Leblanc", "Industrial Analyst", "Hartford", 34, 110000],
+      ["Danny Leon", "Computer Scientist", "Newark", 60, 220000],
+      ["Lane Lee", "Corporate Counselor", "Cincinnati", 52, 180000],
+      ["Jesse Hall", "Business Analyst", "Baltimore", 44, 99000],
+      ["Danni Hudson", "Agency Legal Counsel", "Tampa", 37, 90000],
+      ["Terry Macdonald", "Commercial Specialist", "Miami", 39, 140000],
+      ["Justice Mccarthy", "Attorney", "Tucson", 26, 330000],
+      ["Silver Carey", "Computer Scientist", "Memphis", 47, 250000],
+      ["Franky Miles", "Industrial Analyst", "Buffalo", 49, 190000],
+      ["Glen Nixon", "Corporate Counselor", "Arlington", 44, 80000],
+      ["Gabby Strickland", "Business Process Consultant", "Scottsdale", 26, 45000],
+      ["Mason Ray", "Computer Scientist", "San Francisco", 39, 142000]
+    ];
+
+    const options = {
+      filter: true,
+      selectableRows: true,
+      filterType: 'dropdown',
+      responsive: 'stacked',
+      rowsPerPage: 10,
+      page: 1,
+    };
+
+    return (
+      <MUIDataTable title={"ACME Employee list"} data={data} columns={columns} options={options} />
+    );
+
+  }
+}
+
+ReactDOM.render(<Example />, document.getElementById("app-root"));
diff --git a/src/MUIDataTable.js b/src/MUIDataTable.js
index ef5dfc4..382ff5b 100644
--- a/src/MUIDataTable.js
+++ b/src/MUIDataTable.js
@@ -63,6 +63,9 @@ class MUIDataTable extends React.Component {
             filter: PropTypes.bool,
             sort: PropTypes.bool,
             download: PropTypes.bool,
+            viewColumns: PropTypes.bool,
+            filterList: PropTypes.array,
+            filterOptions: PropTypes.array,
             customHeadRender: PropTypes.func,
             customBodyRender: PropTypes.func,
           }),
@@ -91,7 +94,6 @@ class MUIDataTable extends React.Component {
       fixedHeader: PropTypes.bool,
       page: PropTypes.number,
       count: PropTypes.number,
-      filterList: PropTypes.array,
       rowsSelected: PropTypes.array,
       rowsPerPage: PropTypes.number,
       rowsPerPageOptions: PropTypes.array,
@@ -210,6 +212,10 @@ class MUIDataTable extends React.Component {
     if (options.expandableRows && options.renderExpandableRow === undefined) {
       throw Error('renderExpandableRow must be provided when using expandableRows option');
     }
+    if (this.props.options.filterList) {
+      console.error('Deprecated: filterList must now be provided under each column option. see https://github.com/gregnb/mui-datatables/tree/master/examples/serverside-options example');
+    }
+
   }
 
   setTableAction = action => {
@@ -219,7 +225,7 @@ class MUIDataTable extends React.Component {
   };
 
   setTableOptions(props) {
-    const optionNames = ['rowsPerPage', 'page', 'rowsSelected', 'filterList', 'rowsPerPageOptions'];
+    const optionNames = ['rowsPerPage', 'page', 'rowsSelected', 'rowsPerPageOptions'];
     const optState = optionNames.reduce((acc, cur) => {
       if (this.options[cur] !== undefined) {
         acc[cur] = this.options[cur];
@@ -243,8 +249,8 @@ class MUIDataTable extends React.Component {
     return cols.map(item => {
       if (typeof item !== 'object') return item;
 
-      const { options, ...otherOpts } = item;
-      return otherOpts;
+      const { options: { customHeadRender, customBodyRender, setCellProps, ...otherOptions }, ...otherProps } = item;
+      return { ...otherOptions, ...otherProps };
     });
   };
 
@@ -268,6 +274,7 @@ class MUIDataTable extends React.Component {
         filter: true,
         sort: true,
         download: true,
+        viewColumns: true,
         sortDirection: null,
       };
 
@@ -327,6 +334,14 @@ class MUIDataTable extends React.Component {
         if (filterData[colIndex].indexOf(value) < 0) filterData[colIndex].push(value);
       }
 
+      if (column.filterOptions) {
+        filterData[colIndex] = cloneDeep(column.filterOptions);
+      }
+
+      if (column.filterList) {
+        filterList[colIndex] = cloneDeep(column.filterList);
+      }
+
       if (this.options.sortFilterList) {
         const comparator = getCollatorComparator();
         filterData[colIndex].sort(comparator);
@@ -338,12 +353,6 @@ class MUIDataTable extends React.Component {
       }
     });
 
-    if (options.filterList) filterList = options.filterList;
-
-    if (filterList.length !== columns.length) {
-      throw new Error('Provided options.filterList does not match the column length');
-    }
-
     let selectedRowsData = {
       data: [],
       lookup: {},
diff --git a/src/components/TableViewCol.js b/src/components/TableViewCol.js
index 5d72339..79dbd65 100644
--- a/src/components/TableViewCol.js
+++ b/src/components/TableViewCol.js
@@ -69,7 +69,7 @@ class TableViewCol extends React.Component {
         <FormGroup className={classes.formGroup}>
           {columns.map((column, index) => {
             return (
-              column.display !== 'excluded' && (
+              column.display !== 'excluded' && column.viewColumns !== false && (
                 <FormControlLabel
                   key={index}
                   classes={{
diff --git a/webpack.config.js b/webpack.config.js
index 001e1b0..6a2037e 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -3,7 +3,7 @@ const webpack = require('webpack');
 
 module.exports = {
   entry: {
-    app: "./examples/expandable-rows/index.js"
+    app: "./examples/column-filters/index.js"
   },
   stats: "verbose",
   context: __dirname,


Test patch:
diff --git a/test/MUIDataTable.test.js b/test/MUIDataTable.test.js
index 377c988..6fe1ce8 100644
--- a/test/MUIDataTable.test.js
+++ b/test/MUIDataTable.test.js
@@ -85,19 +85,21 @@ describe('<MUIDataTable />', function() {
         filter: true,
         download: true,
         sortDirection: null,
+        viewColumns: true,
         customBodyRender: renderName,
       },
-      { display: 'true', name: 'Company', sort: true, filter: true, download: true, sortDirection: null },
+      { display: 'true', name: 'Company', sort: true, filter: true, download: true, viewColumns: true, sortDirection: null },
       {
         display: 'true',
         name: 'City',
         sort: true,
         filter: true,
         download: true,
+        viewColumns: true,
         sortDirection: null,
         customBodyRender: renderCities,
       },
-      { display: 'true', name: 'State', sort: true, filter: true, download: true, sortDirection: null },
+      { display: 'true', name: 'State', sort: true, filter: true, download: true, viewColumns: true, sortDirection: null },
     ];
 
     assert.deepEqual(actualResult, expectedResult);
@@ -345,8 +347,9 @@ describe('<MUIDataTable />', function() {
         download: true,
         sortDirection: null,
         customBodyRender: renderName,
+        viewColumns: true,
       },
-      { name: 'Company', display: 'true', sort: true, filter: true, download: true, sortDirection: null },
+      { name: 'Company', display: 'true', sort: true, filter: true, download: true, viewColumns: true, sortDirection: null },
       {
         name: 'City',
         display: 'true',
@@ -355,8 +358,9 @@ describe('<MUIDataTable />', function() {
         download: true,
         sortDirection: null,
         customBodyRender: renderCities,
+        viewColumns: true,
       },
-      { name: 'State', display: 'true', sort: true, filter: true, download: true, sortDirection: null },
+      { name: 'State', display: 'true', sort: true, filter: true, download: true, viewColumns: true, sortDirection: null },
     ];
 
     assert.deepEqual(state.columns, expectedResult);