diff --git a/docs/columns.md b/docs/columns.md
index d472e67..afeffe7 100644
--- a/docs/columns.md
+++ b/docs/columns.md
@@ -7,6 +7,7 @@ Available properties in a column object:
* [text (**required**)](#text)
#### Optional
+* [isDummyField](#isDummyField)
* [hidden](#hidden)
* [formatter](#formatter)
* [formatExtraData](#formatExtraData)
@@ -84,6 +85,11 @@ dataField: 'address.city'
## column.text (**required**) - [String]
`text` will be the column text in header column by default, if your header is not only text or you want to customize the header column, please check [`column.headerFormatter`](#headerFormatter)
+## column.isDummyField - [Bool]
+Sometime, you just want to have a column which is not perform any data but just some action components. In this situation, we suggest you to use `isDummyField`. If column is dummy, the [`column.dataField`](#dataField) can be any string value, cause of it's meaningless.
+
+There's only one different for dummy column than normal column, which is dummy column will compare the whole row value instead of cell value when call `shouldComponentUpdate`.
+
## column.hidden - [Bool]
`hidden` allow you to hide column when `true` given.
diff --git a/packages/react-bootstrap-table2-example/examples/columns/dummy-column-table.js b/packages/react-bootstrap-table2-example/examples/columns/dummy-column-table.js
new file mode 100644
index 0000000..10b6948
--- /dev/null
+++ b/packages/react-bootstrap-table2-example/examples/columns/dummy-column-table.js
@@ -0,0 +1,221 @@
+/* eslint jsx-a11y/label-has-for: 0 */
+import React from 'react';
+
+import BootstrapTable from 'react-bootstrap-table-next';
+import Code from 'components/common/code-block';
+
+
+const products = [
+ { id: 12, name: 'Item 12', price: 12.5, inStock: false },
+ { id: 13, name: 'Item 13', price: 13.5, inStock: true },
+ { id: 14, name: 'Item 14', price: 14.5, inStock: true }
+];
+
+const columns = [
+ {
+ dataField: 'id',
+ text: 'Product ID'
+ },
+ {
+ dataField: 'name',
+ text: 'Product Name'
+ },
+ {
+ dataField: 'price',
+ text: 'Product Price'
+ },
+ {
+ dataField: 'inStock',
+ text: 'In Stock',
+ formatter: (cellContent, row) => (
+
+
+
+
+
+ )
+ },
+ {
+ dataField: 'df1',
+ isDummyField: true,
+ text: 'Action 1',
+ formatter: (cellContent, row) => {
+ if (row.inStock) {
+ return (
+
+ Available
+
+ );
+ }
+ return (
+
+ Backordered
+
+ );
+ }
+ },
+ {
+ dataField: 'df2',
+ isDummyField: true,
+ text: 'Action 2',
+ formatter: (cellContent, row) => {
+ if (row.inStock) {
+ return (
+
+ Available
+
+ );
+ }
+ return (
+
+ Backordered
+
+ );
+ }
+ }
+];
+
+const sourceCode = `\
+import BootstrapTable from 'react-bootstrap-table-next';
+
+const columns = [
+ {
+ dataField: 'id',
+ text: 'Product ID'
+ },
+ {
+ dataField: 'name',
+ text: 'Product Name'
+ },
+ {
+ dataField: 'price',
+ text: 'Product Price'
+ },
+ {
+ dataField: 'inStock',
+ text: 'In Stock',
+ formatter: (cellContent, row) => (
+
+
+
+
+
+ )
+ },
+ {
+ dataField: 'df1',
+ isDummyField: true,
+ text: 'Action 1',
+ formatter: (cellContent, row) => {
+ if (row.inStock) {
+ return (
+
+ Available
+
+ );
+ }
+ return (
+
+ Backordered
+
+ );
+ }
+ },
+ {
+ dataField: 'df2',
+ isDummyField: true,
+ text: 'Action 2',
+ formatter: (cellContent, row) => {
+ if (row.inStock) {
+ return (
+
+ Available
+
+ );
+ }
+ return (
+
+ Backordered
+
+ );
+ }
+ }
+];
+
+class ProductList extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = { products };
+ }
+
+ toggleInStock = () => {
+ let newProducts = [...this.state.products];
+ newProducts = newProducts.map((d) => {
+ if (d.id === 13) {
+ return {
+ ...d,
+ inStock: !d.inStock
+ };
+ }
+ return d;
+ });
+ this.setState(curr => ({ ...curr, products: newProducts }));
+ };
+
+ render() {
+ return (
+
+
Products
+
+
+ Toggle item 13 stock status
+
+
+ );
+ }
+}
+`;
+
+class ProductList extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = { products };
+ }
+
+ toggleInStock = () => {
+ let newProducts = [...this.state.products];
+ newProducts = newProducts.map((d) => {
+ if (d.id === 13) {
+ return {
+ ...d,
+ inStock: !d.inStock
+ };
+ }
+ return d;
+ });
+ this.setState(curr => ({ ...curr, products: newProducts }));
+ };
+
+ render() {
+ return (
+
+
Action 1 and Action 2 are dummy column
+
+ Toggle item 13 stock status
+
+
+ { sourceCode }
+
+ );
+ }
+}
+
+export default ProductList;
diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js
index eff1ee0..45fb5cc 100644
--- a/packages/react-bootstrap-table2-example/stories/index.js
+++ b/packages/react-bootstrap-table2-example/stories/index.js
@@ -30,6 +30,7 @@ import ColumnTitleTable from 'examples/columns/column-title-table';
import ColumnEventTable from 'examples/columns/column-event-table';
import ColumnHiddenTable from 'examples/columns/column-hidden-table';
import ColumnAttrsTable from 'examples/columns/column-attrs-table';
+import DummyColumnTable from 'examples/columns/dummy-column-table';
// work on header columns
import HeaderColumnFormatTable from 'examples/header-columns/column-format-table';
@@ -201,7 +202,8 @@ storiesOf('Work on Columns', module)
.add('Column Event', () => )
.add('Customize Column Class', () => )
.add('Customize Column Style', () => )
- .add('Customize Column HTML attribute', () => );
+ .add('Customize Column HTML attribute', () => )
+ .add('Dummy Column', () => );
storiesOf('Work on Header Columns', module)
.addDecorator(bootstrapStyle())
diff --git a/packages/react-bootstrap-table2/src/cell.js b/packages/react-bootstrap-table2/src/cell.js
index db32d05..e6f2149 100644
--- a/packages/react-bootstrap-table2/src/cell.js
+++ b/packages/react-bootstrap-table2/src/cell.js
@@ -11,9 +11,18 @@ class Cell extends Component {
}
shouldComponentUpdate(nextProps) {
- const shouldUpdate =
- _.get(this.props.row, this.props.column.dataField)
- !== _.get(nextProps.row, nextProps.column.dataField) ||
+ let shouldUpdate = false;
+ if (nextProps.column.isDummyField) {
+ shouldUpdate = !_.isEqual(this.props.row, nextProps.row);
+ } else {
+ shouldUpdate =
+ _.get(this.props.row, this.props.column.dataField)
+ !== _.get(nextProps.row, nextProps.column.dataField);
+ }
+
+ if (shouldUpdate) return true;
+
+ shouldUpdate =
this.props.column.hidden !== nextProps.column.hidden ||
this.props.rowIndex !== nextProps.rowIndex ||
this.props.columnIndex !== nextProps.columnIndex ||
@@ -64,7 +73,7 @@ class Cell extends Component {
formatExtraData
} = column;
const attrs = { ...rest };
- let content = _.get(row, dataField);
+ let content = column.isDummyField ? null : _.get(row, dataField);
if (formatter) {
content = column.formatter(content, row, rowIndex, formatExtraData);
diff --git a/packages/react-bootstrap-table2/src/header-cell.js b/packages/react-bootstrap-table2/src/header-cell.js
index 52cf7a1..2053453 100644
--- a/packages/react-bootstrap-table2/src/header-cell.js
+++ b/packages/react-bootstrap-table2/src/header-cell.js
@@ -114,6 +114,7 @@ HeaderCell.propTypes = {
column: PropTypes.shape({
dataField: PropTypes.string.isRequired,
text: PropTypes.string.isRequired,
+ isDummyField: PropTypes.bool,
hidden: PropTypes.bool,
headerFormatter: PropTypes.func,
formatter: PropTypes.func,
diff --git a/packages/react-bootstrap-table2/test/cell.test.js b/packages/react-bootstrap-table2/test/cell.test.js
index 86bf393..e2e42ab 100644
--- a/packages/react-bootstrap-table2/test/cell.test.js
+++ b/packages/react-bootstrap-table2/test/cell.test.js
@@ -177,22 +177,45 @@ describe('Cell', () => {
let props;
let nextProps;
- describe('when content is change', () => {
- const column = { dataField: 'name', text: 'Product Name' };
- beforeEach(() => {
- props = {
- row,
- columnIndex: 1,
- rowIndex: 1,
- column
- };
- wrapper = shallow(
- | );
- });
+ describe('if column.isDummyField is false', () => {
+ describe('when content is change', () => {
+ const column = { dataField: 'name', text: 'Product Name' };
+ beforeEach(() => {
+ props = {
+ row,
+ columnIndex: 1,
+ rowIndex: 1,
+ column
+ };
+ wrapper = shallow(
+ | );
+ });
- it('should return true', () => {
- nextProps = { ...props, row: { id: 1, name: 'CDE' } };
- expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(true);
+ it('should return true', () => {
+ nextProps = { ...props, row: { id: 1, name: 'CDE' } };
+ expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(true);
+ });
+ });
+ });
+
+ describe('if column.isDummyField is true', () => {
+ describe('when content is change', () => {
+ const column = { dataField: '', text: 'Product Name', isDummyField: true };
+ beforeEach(() => {
+ props = {
+ row,
+ columnIndex: 1,
+ rowIndex: 1,
+ column
+ };
+ wrapper = shallow(
+ | );
+ });
+
+ it('should return true', () => {
+ nextProps = { ...props, row: { id: 1, name: 'CDE', test: 'This is new Field' } };
+ expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(true);
+ });
});
});