Repository: gregnb/mui-datatables
Pull request #470 (2019-03-06 22:01:32)

Missing data for custom action columns
Addresses https://github.com/gregnb/mui-datatables/issues/443.

There were two issues.

1. Missing fields in data were causing errors
1. Data arrays of arrays did not properly render `customBodyRender` when data was missing

Added an example under `custom-action-columns`. Not sure what the best name for this kind of use case would be, so I'm open to suggestions.

Let me know what you think.

UPDATED:

~~Added an API option for columns called `hasData` which defaults to `true`. When `false`, it signifies that a column should be skipped when checking for data. This is only relevant for the array of arrays data structure, but allows full use of empty columns or `customBodyRender` in those cases.~~

~~Not sure that the API option is super obvious, but I couldn't think of another way to distinguish data in the array of arrays structure as intentionally absent.~~

Added an API option for columns called `empty` which defaults to `false`. When `true`, it signifies that a column should be skipped when checking for data. This is only relevant for the array of arrays data structure, but allows full use of empty columns or `customBodyRender` in those cases.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/22030588/badge)](https://coveralls.io/builds/22030588)

Coverage increased (+0.01%) to 72.093% when pulling **02868b08814a3bd2310176d8a52a1e6b146eaf7f on gabrielliwerant:issue-443** into **e9938b8f3ac4fa06e05d52d2596fd3411148d57c on gregnb:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/22030393/badge)](https://coveralls.io/builds/22030393)

Coverage increased (+0.04%) to 72.12% when pulling **da2c12bf2fa897fd1704d7017b8bca743bd23bd8 on gabrielliwerant:issue-443** into **e9938b8f3ac4fa06e05d52d2596fd3411148d57c on gregnb:master**.

gabrielliwerant: Just noticed an edge case here where no-data columns other than the last row cause the indexing to get messed up when transformed. Working on it and will push fixes here.
gregnb: What if we named it `empty` instead? and make the README something like `This denotes with the column has data or not` ?
gabrielliwerant: Updated with the API change.
gregnb: Ok great! I'll review this if I can get some free time tonight. Thanks again
gregnb: @gabrielliwerant Approved. I will merge this when I do the next release in the next couple of days

Patch:
diff --git a/README.md b/README.md
index 68fbf4b..d726ee6 100644
--- a/README.md
+++ b/README.md
@@ -206,6 +206,7 @@ const columns = [
 |Name|Type|Default|Description
 |:--:|:-----|:--|:-----|
 |**`display`**|string|'true'|Display column in table. `enum('true', 'false', 'excluded')`
+|**`empty`**|boolean|false|This denotes whether the column has data or not (for use with intentionally empty columns)
 |**`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
diff --git a/examples/custom-action-columns/index.js b/examples/custom-action-columns/index.js
new file mode 100644
index 0000000..6435bbb
--- /dev/null
+++ b/examples/custom-action-columns/index.js
@@ -0,0 +1,154 @@
+import React from "react";
+import ReactDOM from "react-dom";
+import MUIDataTable from "../../src/";
+
+class Example extends React.Component {
+
+  render() {
+
+    const columns = [
+      {
+        name: "Edit",
+        options: {
+          filter: true,
+          sort: false,
+          empty: true,
+          customBodyRender: (value, tableMeta, updateValue) => {
+            return (
+              <button onClick={() => window.alert(`Clicked "Edit" for row ${tableMeta.rowIndex}`)}>
+                Edit
+              </button>
+            );
+          }
+        }
+      },
+      {
+        name: "Name",
+        options: {
+          filter: true,
+        }
+      },
+      {
+        label: "Modified Title Label",
+        name: "Title",
+        options: {
+          filter: true,
+        }
+      },
+      {
+        name: "Location",
+        options: {
+          filter: false,
+        }
+      },
+      {
+        name: "Age",
+        options: {
+          filter: true,
+        }
+      },
+      {
+        name: "Salary",
+        options: {
+          filter: true,
+          sort: false,
+        }
+      },
+      {
+        name: "Add",
+        options: {
+          filter: true,
+          sort: false,
+          empty: true,
+          customBodyRender: (value, tableMeta, updateValue) => {
+            return (
+              <button onClick={() => window.alert(`Clicked "Add" for row ${tableMeta.rowIndex}`)}>
+                Add
+              </button>
+            );
+          }
+        }
+      },
+    ];
+
+
+    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", "Omaha", 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 data1 = [
+      {Name: "Gabby George", Title: "Business Analyst", Location: "Minneapolis", Age: 30, Salary: "$100,000"},
+      {Name: "Aiden Lloyd", Title: "Business Consultant", Location: "Dallas", Age: 55, Salary: "$200,000"},
+      {Name: "Jaden Collins", Title: "Attorney", Location: "Santa Ana", Age: 27, Salary: "$500,000"},
+      {Name: "Franky Rees", Title: "Business Analyst", Location: "St. Petersburg", Age: 22, Salary: "$50,000"},
+      {Name: "Aaren Rose", Title: "Business Consultant", Location: "Toledo", Age: 28, Salary: "$75,000"},
+      {Name: "Blake Duncan", Title: "Business Management Analyst", Location: "San Diego", Age: 65, Salary: "$94,000"},
+      {Name: "Frankie Parry", Title: "Agency Legal Counsel", Location: "Jacksonville", Age: 71, Salary: "$210,000"},
+      {Name: "Lane Wilson", Title: "Commercial Specialist", Location: "Omaha", Age: 19, Salary: "$65,000"},
+      {Name: "Robin Duncan", Title: "Business Analyst", Location: "Los Angeles", Age: 20, Salary: "$77,000"},
+      {Name: "Mel Brooks", Title: "Business Consultant", Location: "Oklahoma City", Age: 37, Salary: "$135,000"},
+      {Name: "Harper White", Title: "Attorney", Location: "Pittsburgh", Age: 52, Salary: "$420,000"},
+      {Name: "Kris Humphrey", Title: "Agency Legal Counsel", Location: "Laredo", Age: 30, Salary: "$150,000"},
+      {Name: "Frankie Long", Title: "Industrial Analyst", Location: "Austin", Age: 31, Salary: "$170,000"},
+      {Name: "Brynn Robbins", Title: "Business Analyst", Location: "Norfolk", Age: 22, Salary: "$90,000"},
+      {Name: "Justice Mann", Title: "Business Consultant", Location: "Chicago", Age: 24, Salary: "$133,000"},
+      {Name: "Addison Navarro", Title: "Business Management Analyst", Location: "New York", Age: 50, Salary: "$295,000"},
+      {Name: "Jesse Welch", Title: "Agency Legal Counsel", Location: "Seattle", Age: 28, Salary: "$200,000"},
+      {Name: "Eli Mejia", Title: "Commercial Specialist", Location: "Long Beach", Age: 65, Salary: "$400,000"},
+      {Name: "Gene Leblanc", Title: "Industrial Analyst", Location: "Hartford", Age: 34, Salary: "$110,000"},
+      {Name: "Danny Leon", Title: "Computer Scientist", Location: "Newark", Age: 60, Salary: "$220,000"},
+      {Name: "Lane Lee", Title: "Corporate Counselor", Location: "Cincinnati", Age: 52, Salary: "$180,000"},
+      {Name: "Jesse Hall", Title: "Business Analyst", Location: "Baltimore", Age: 44, Salary: "$99,000"},
+      {Name: "Danni Hudson", Title: "Agency Legal Counsel", Location: "Tampa", Age: 37, Salary: "$90,000"},
+      {Name: "Terry Macdonald", Title: "Commercial Specialist", Location: "Miami", Age: 39, Salary: "$140,000"},
+      {Name: "Justice Mccarthy", Title: "Attorney", Location: "Tucson", Age: 26, Salary: "$330,000"},
+      {Name: "Silver Carey", Title: "Computer Scientist", Location: "Memphis", Age: 47, Salary: "$250,000" },
+      {Name: "Franky Miles", Title: "Industrial Analyst", Location: "Buffalo", Age: 49, Salary: "$190,000"},
+      {Name: "Glen Nixon", Title: "Corporate Counselor", Location: "Arlington", Age: 44, Salary: "$80,000"},
+      {Name: "Gabby Strickland", Title: "Business Process Consultant", Location: "Scottsdale", Age: 26, Salary: "$45,000"},
+      {Name: "Mason Ray", Title: "Computer Scientist", Location: "San Francisco", Age: 39, Salary: "$142,000"}
+    ];
+
+    const options = {
+      filter: true,
+      filterType: 'dropdown',
+      responsive: 'stacked',
+    };
+
+    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 4c37a90..0a623cd 100644
--- a/src/MUIDataTable.js
+++ b/src/MUIDataTable.js
@@ -64,6 +64,7 @@ class MUIDataTable extends React.Component {
           name: PropTypes.string.isRequired,
           options: PropTypes.shape({
             display: PropTypes.string, // enum('true', 'false', 'excluded')
+            empty: PropTypes.bool,
             filter: PropTypes.bool,
             sort: PropTypes.bool,
             searchable: PropTypes.bool,
@@ -293,6 +294,7 @@ class MUIDataTable extends React.Component {
     newColumns.forEach((column, colIndex) => {
       let columnOptions = {
         display: 'true',
+        empty: false,
         filter: true,
         sort: true,
         searchable: true,
@@ -325,11 +327,19 @@ class MUIDataTable extends React.Component {
     return { columns: columnData, filterData, filterList };
   };
 
-  transformData = props => {
-    const { data, columns } = props;
-    return Array.isArray(data[0]) ? data : data.map(row => columns.map(col => row[col.name]));
-  };
+  transformData = (columns, data) => {
+    return Array.isArray(data[0])
+      ? data.map(row => {
+        let i = -1;
 
+        return columns.map(col => {
+          if (!col.empty) i++;
+          return col.empty ? undefined : row[i];
+        });
+      })
+      : data.map(row => columns.map(col => row[col.name]));
+  }
+  
   setTableData(props, status, callback = () => {}) {
     const { options } = props;
 
@@ -338,7 +348,7 @@ class MUIDataTable extends React.Component {
     let sortIndex = null;
     let sortDirection = null;
 
-    const data = status === TABLE_LOAD.INITIAL ? this.transformData(props) : props.data;
+    const data = status === TABLE_LOAD.INITIAL ? this.transformData(columns, props.data) : props.data;
 
     columns.forEach((column, colIndex) => {
       for (let rowIndex = 0; rowIndex < data.length; rowIndex++) {
@@ -454,7 +464,7 @@ class MUIDataTable extends React.Component {
 
       displayRow.push(columnDisplay);
 
-      const columnVal = columnValue === null ? '' : columnValue.toString();
+      const columnVal = columnValue === null || columnValue === undefined ? '' : columnValue.toString();
 
       const filterVal = filterList[index];
       const { filterType, caseSensitive } = this.options;


Test patch:
diff --git a/test/MUIDataTable.test.js b/test/MUIDataTable.test.js
index 42e2899..e0183ca 100644
--- a/test/MUIDataTable.test.js
+++ b/test/MUIDataTable.test.js
@@ -26,6 +26,7 @@ describe('<MUIDataTable />', function() {
       'Company',
       { name: 'City', label: 'City Label', options: { customBodyRender: renderCities } },
       { name: 'State' },
+      { name: 'Empty', options: { empty: true } }
     ];
     data = [
       ['Joe James', 'Test Corp', 'Yonkers', 'NY'],
@@ -36,27 +37,27 @@ describe('<MUIDataTable />', function() {
     // internal table data built from source data provided
     displayData = JSON.stringify([
       {
-        data: ['James, Joe', 'Test Corp', renderCities('Yonkers', { rowIndex: 0 }), 'NY'],
+        data: ['James, Joe', 'Test Corp', renderCities('Yonkers', { rowIndex: 0 }), 'NY', undefined],
         dataIndex: 0,
       },
       {
-        data: ['Walsh, John', 'Test Corp', renderCities('Hartford', { rowIndex: 1 }), 'CT'],
+        data: ['Walsh, John', 'Test Corp', renderCities('Hartford', { rowIndex: 1 }), 'CT', undefined],
         dataIndex: 1,
       },
       {
-        data: ['Herm, Bob', 'Test Corp', renderCities('Tampa', { rowIndex: 2 }), 'FL'],
+        data: ['Herm, Bob', 'Test Corp', renderCities('Tampa', { rowIndex: 2 }), 'FL', undefined],
         dataIndex: 2,
       },
       {
-        data: ['Houston, James', 'Test Corp', renderCities('Dallas', { rowIndex: 3 }), 'TX'],
+        data: ['Houston, James', 'Test Corp', renderCities('Dallas', { rowIndex: 3 }), 'TX', undefined],
         dataIndex: 3,
       },
     ]);
     tableData = [
-      { index: 0, data: ['James, Joe', 'Test Corp', renderCities('Yonkers', { rowIndex: 0 }), 'NY'] },
-      { index: 1, data: ['Walsh, John', 'Test Corp', renderCities('Hartford', { rowIndex: 1 }), 'CT'] },
-      { index: 2, data: ['Herm, Bob', 'Test Corp', renderCities('Tampa', { rowIndex: 2 }), 'FL'] },
-      { index: 3, data: ['Houston, James', 'Test Corp', renderCities('Dallas', { rowIndex: 3 }), 'TX'] },
+      { index: 0, data: ['James, Joe', 'Test Corp', renderCities('Yonkers', { rowIndex: 0 }), 'NY', undefined] },
+      { index: 1, data: ['Walsh, John', 'Test Corp', renderCities('Hartford', { rowIndex: 1 }), 'CT', undefined] },
+      { index: 2, data: ['Herm, Bob', 'Test Corp', renderCities('Tampa', { rowIndex: 2 }), 'FL', undefined] },
+      { index: 3, data: ['Houston, James', 'Test Corp', renderCities('Dallas', { rowIndex: 3 }), 'TX', undefined] },
     ];
     renderCities = renderCities;
     renderName = renderName;
@@ -80,6 +81,7 @@ describe('<MUIDataTable />', function() {
     const expectedResult = [
       {
         display: 'true',
+        empty: false,
         name: 'Name',
         sort: true,
         filter: true,
@@ -92,6 +94,7 @@ describe('<MUIDataTable />', function() {
       },
       {
         display: 'true',
+        empty: false,
         name: 'Company',
         sort: true,
         filter: true,
@@ -103,6 +106,7 @@ describe('<MUIDataTable />', function() {
       },
       {
         display: 'true',
+        empty: false,
         name: 'City',
         sort: true,
         filter: true,
@@ -115,6 +119,7 @@ describe('<MUIDataTable />', function() {
       },
       {
         display: 'true',
+        empty: false,
         name: 'State',
         sort: true,
         filter: true,
@@ -124,6 +129,18 @@ describe('<MUIDataTable />', function() {
         viewColumns: true,
         sortDirection: null,
       },
+      {
+        display: 'true',
+        empty: true,
+        name: 'Empty',
+        sort: true,
+        filter: true,
+        label: 'Empty',
+        download: true,
+        searchable: true,
+        viewColumns: true,
+        sortDirection: null,
+      },
     ];
 
     assert.deepEqual(actualResult, expectedResult);
@@ -150,10 +167,10 @@ describe('<MUIDataTable />', function() {
 
     state = shallowWrapper.dive().state();
     const expectedResult = [
-      { index: 0, data: ['testing', 'Test Corp', 'Yonkers', 'NY'] },
-      { index: 1, data: ['John Walsh', 'Test Corp', 'Hartford', 'CT'] },
-      { index: 2, data: ['Bob Herm', 'Test Corp', 'Tampa', 'FL'] },
-      { index: 3, data: ['James Houston', 'Test Corp', 'Dallas', 'TX'] },
+      { index: 0, data: ['testing', 'Test Corp', 'Yonkers', 'NY', undefined] },
+      { index: 1, data: ['John Walsh', 'Test Corp', 'Hartford', 'CT', undefined] },
+      { index: 2, data: ['Bob Herm', 'Test Corp', 'Tampa', 'FL', undefined] },
+      { index: 3, data: ['James Houston', 'Test Corp', 'Dallas', 'TX', undefined] },
     ];
 
     assert.deepEqual(state.data, expectedResult);
@@ -179,7 +196,7 @@ describe('<MUIDataTable />', function() {
   it('should correctly build internal filterList structure', () => {
     const shallowWrapper = shallow(<MUIDataTable columns={columns} data={data} />);
     const state = shallowWrapper.dive().state();
-    const expectedResult = [[], [], [], []];
+    const expectedResult = [[], [], [], [], []];
 
     assert.deepEqual(state.filterList, expectedResult);
   });
@@ -192,6 +209,7 @@ describe('<MUIDataTable />', function() {
       ['Test Corp'],
       ['Dallas', 'Hartford', 'Tampa', 'Yonkers'],
       ['CT', 'FL', 'NY', 'TX'],
+      [undefined]
     ];
 
     assert.deepEqual(state.filterData, expectedResult);
@@ -246,7 +264,7 @@ describe('<MUIDataTable />', function() {
     table.update();
 
     const state = table.state();
-    assert.deepEqual(state.filterList, [['Joe James'], [], [], []]);
+    assert.deepEqual(state.filterList, [['Joe James'], [], [], [], []]);
   });
 
   it('should remove entry from filterList when calling filterUpdate method with type=checkbox and same arguments a second time', () => {
@@ -257,13 +275,13 @@ describe('<MUIDataTable />', function() {
     table.update();
 
     let state = table.state();
-    assert.deepEqual(state.filterList, [['Joe James'], [], [], []]);
+    assert.deepEqual(state.filterList, [['Joe James'], [], [], [], []]);
 
     instance.filterUpdate(0, 'Joe James', 'checkbox');
     table.update();
 
     state = table.state();
-    assert.deepEqual(state.filterList, [[], [], [], []]);
+    assert.deepEqual(state.filterList, [[], [], [], [], []]);
   });
 
   it('should properly set internal filterList when calling filterUpdate method with type=dropdown', () => {
@@ -274,11 +292,11 @@ describe('<MUIDataTable />', function() {
     table.update();
 
     const state = table.state();
-    assert.deepEqual(state.filterList, [['Joe James'], [], [], []]);
+    assert.deepEqual(state.filterList, [['Joe James'], [], [], [], []]);
   });
 
   it('should create Chip when filterList is populated', () => {
-    const filterList = [['Joe James'], [], [], []];
+    const filterList = [['Joe James'], [], [], [], []];
 
     const mountWrapper = mount(<TableFilterList filterList={filterList} filterUpdate={() => true} />);
     const actualResult = mountWrapper.find(Chip);
@@ -293,13 +311,13 @@ describe('<MUIDataTable />', function() {
     table.update();
 
     let state = table.state();
-    assert.deepEqual(state.filterList, [['Joe James'], [], [], []]);
+    assert.deepEqual(state.filterList, [['Joe James'], [], [], [], []]);
 
     instance.filterUpdate(0, 'Joe James', 'dropdown');
     table.update();
 
     state = table.state();
-    assert.deepEqual(state.filterList, [[], [], [], []]);
+    assert.deepEqual(state.filterList, [[], [], [], [], []]);
   });
 
   it('should properly reset internal filterList when calling resetFilters method', () => {
@@ -312,12 +330,12 @@ describe('<MUIDataTable />', function() {
 
     // now remove it
     let state = table.state();
-    assert.deepEqual(state.filterList, [['Joe James'], [], [], []]);
+    assert.deepEqual(state.filterList, [['Joe James'], [], [], [], []]);
 
     instance.resetFilters();
     table.update();
     state = table.state();
-    assert.deepEqual(state.filterList, [[], [], [], []]);
+    assert.deepEqual(state.filterList, [[], [], [], [], []]);
   });
 
   it('should properly set searchText when calling searchTextUpdate method', () => {
@@ -330,7 +348,7 @@ describe('<MUIDataTable />', function() {
     const state = table.state();
 
     const expectedResult = JSON.stringify([
-      { data: ['James, Joe', 'Test Corp', renderCities('Yonkers', { rowIndex: 0 }), 'NY'], dataIndex: 0 },
+      { data: ['James, Joe', 'Test Corp', renderCities('Yonkers', { rowIndex: 0 }), 'NY', undefined], dataIndex: 0 },
     ]);
 
     assert.deepEqual(JSON.stringify(state.displayData), expectedResult);
@@ -345,10 +363,10 @@ describe('<MUIDataTable />', function() {
     const state = shallowWrapper.state();
 
     const expectedResult = JSON.stringify([
-      { data: ['Herm, Bob', 'Test Corp', renderCities('Tampa', { rowIndex: 0 }), 'FL'], dataIndex: 2 },
-      { data: ['Houston, James', 'Test Corp', renderCities('Dallas', { rowIndex: 1 }), 'TX'], dataIndex: 3 },
-      { data: ['James, Joe', 'Test Corp', renderCities('Yonkers', { rowIndex: 2 }), 'NY'], dataIndex: 0 },
-      { data: ['Walsh, John', 'Test Corp', renderCities('Hartford', { rowIndex: 3 }), 'CT'], dataIndex: 1 },
+      { data: ['Herm, Bob', 'Test Corp', renderCities('Tampa', { rowIndex: 0 }), 'FL', undefined], dataIndex: 2 },
+      { data: ['Houston, James', 'Test Corp', renderCities('Dallas', { rowIndex: 1 }), 'TX', undefined], dataIndex: 3 },
+      { data: ['James, Joe', 'Test Corp', renderCities('Yonkers', { rowIndex: 2 }), 'NY', undefined], dataIndex: 0 },
+      { data: ['Walsh, John', 'Test Corp', renderCities('Hartford', { rowIndex: 3 }), 'CT', undefined], dataIndex: 1 },
     ]);
 
     assert.deepEqual(JSON.stringify(state.displayData), expectedResult);
@@ -366,6 +384,7 @@ describe('<MUIDataTable />', function() {
       {
         name: 'Name',
         display: 'false',
+        empty: false,
         sort: true,
         filter: true,
         label: 'Name',
@@ -378,6 +397,7 @@ describe('<MUIDataTable />', function() {
       {
         name: 'Company',
         display: 'true',
+        empty: false,
         sort: true,
         filter: true,
         label: 'Company',
@@ -389,6 +409,7 @@ describe('<MUIDataTable />', function() {
       {
         name: 'City',
         display: 'true',
+        empty: false,
         sort: true,
         filter: true,
         label: 'City Label',
@@ -401,6 +422,7 @@ describe('<MUIDataTable />', function() {
       {
         name: 'State',
         display: 'true',
+        empty: false,
         sort: true,
         filter: true,
         label: 'State',
@@ -409,6 +431,18 @@ describe('<MUIDataTable />', function() {
         viewColumns: true,
         sortDirection: null,
       },
+      {
+        name: 'Empty',
+        display: 'true',
+        empty: true,
+        sort: true,
+        filter: true,
+        label: 'Empty',
+        download: true,
+        searchable: true,
+        viewColumns: true,
+        sortDirection: null,
+      },
     ];
 
     assert.deepEqual(state.columns, expectedResult);
@@ -566,7 +600,7 @@ describe('<MUIDataTable />', function() {
     const state = table.state();
 
     const expectedResult = JSON.stringify([
-      { data: ['James, Joe', 'Test Corp', renderCities('Yonkers', { rowIndex: 0 }), 'NY'], dataIndex: 0 },
+      { data: ['James, Joe', 'Test Corp', renderCities('Yonkers', { rowIndex: 0 }), 'NY', undefined], dataIndex: 0 },
     ]);
 
     assert.deepEqual(JSON.stringify(state.displayData), expectedResult);
@@ -582,8 +616,8 @@ describe('<MUIDataTable />', function() {
     const state = table.state();
 
     const expectedResult = JSON.stringify([
-      { data: ['James, Joe', 'Test Corp', renderCities('Yonkers', { rowIndex: 0 }), 'NY'], dataIndex: 0 },
-      { data: ['Houston, James', 'Test Corp', renderCities('Dallas', { rowIndex: 3 }), 'TX'], dataIndex: 3 },
+      { data: ['James, Joe', 'Test Corp', renderCities('Yonkers', { rowIndex: 0 }), 'NY', undefined], dataIndex: 0 },
+      { data: ['Houston, James', 'Test Corp', renderCities('Dallas', { rowIndex: 3 }), 'TX', undefined], dataIndex: 3 },
     ]);
 
     assert.deepEqual(JSON.stringify(state.displayData), expectedResult);