From 4abe39ce2710cba33ef8066f8187a7cb3432ec5e Mon Sep 17 00:00:00 2001 From: Griffin Smith Date: Wed, 30 Sep 2015 01:02:06 -0400 Subject: [PATCH] Allow specifying table rows in custom components Use the structure returned by `react.createElement` to do a render of any child components with unrecognized types, and extract the data out of them if they themselves return a `` --- build/reactable.js | 23 +++++++++--- build/tests/reactable_test.js | 69 +++++++++++++++++++++++++++++++++++ lib/reactable/table.js | 23 +++++++++--- src/reactable/table.jsx | 20 +++++++--- tests/reactable_test.jsx | 7 ++-- 5 files changed, 124 insertions(+), 18 deletions(-) diff --git a/build/reactable.js b/build/reactable.js index 463dc9cc..6285eb78 100644 --- a/build/reactable.js +++ b/build/reactable.js @@ -1033,6 +1033,9 @@ window.React["default"] = window.React; } }).bind(this)); } + }, { + key: 'childType', + value: function childType(child) {} }, { key: 'parseChildData', value: function parseChildData(props) { @@ -1046,7 +1049,17 @@ window.React["default"] = window.React; return; } - switch (child.type) { + var reactableDescendant = undefined; + var test = undefined; + + if ([_tfoot.Tfoot, _thead.Thead, _tr.Tr].indexOf(child.type) >= 0) { + reactableDescendant = child; + } else { + reactableDescendant = new child.type(child.props).render(); + test = true; + } + + switch (reactableDescendant.type) { case _tfoot.Tfoot: if (typeof tfoot !== 'undefined') { console.warn('You can only have one , but more than one was specified.' + 'Ignoring all but the last one'); @@ -1054,9 +1067,9 @@ window.React["default"] = window.React; tfoot = child; break; case _tr.Tr: - var childData = child.props.data || {}; + var childData = reactableDescendant.props.data || {}; - _react['default'].Children.forEach(child.props.children, function (descendant) { + _react['default'].Children.forEach(reactableDescendant.props.children, function (descendant) { // TODO /* if (descendant.type.ConvenienceConstructor === Td) { */ if (typeof descendant !== 'object' || descendant == null) { @@ -1069,7 +1082,7 @@ window.React["default"] = window.React; } else if (typeof descendant.props.children !== 'undefined') { value = descendant.props.children; } else { - console.warn('exports.Td specified without ' + 'a `data` property or children, ' + 'ignoring'); + console.warn('Td specified without ' + 'a `data` property or children, ' + 'ignoring'); return; } @@ -1085,7 +1098,7 @@ window.React["default"] = window.React; data.push({ data: childData, - props: (0, _libFilter_props_from.filterPropsFrom)(child.props), + props: (0, _libFilter_props_from.filterPropsFrom)(reactableDescendant.props), __reactableMeta: true }); break; diff --git a/build/tests/reactable_test.js b/build/tests/reactable_test.js index 6bf0bfb9..7e2c3770 100644 --- a/build/tests/reactable_test.js +++ b/build/tests/reactable_test.js @@ -610,6 +610,75 @@ }); }); + describe('adding s to the ', function () { + before(function () { + var CustomComponent = React.createClass({ + displayName: "CustomComponent", + propTypes: { + name: React.PropTypes.string, + age: React.PropTypes.number, + position: React.PropTypes.string + }, + render: function render() { + return React.createElement( + Reactable.Tr, + null, + React.createElement( + Reactable.Td, + { column: 'Name' }, + this.props.name || '' + ), + React.createElement( + Reactable.Td, + { column: 'Age' }, + this.props.age || '' + ), + React.createElement( + Reactable.Td, + { column: 'Position' }, + this.props.position || '' + ) + ); + } + }); + + React.render(React.createElement( + Reactable.Table, + { className: 'table', id: 'table' }, + React.createElement(CustomComponent, { name: 'Griffin Smith', age: 18 }), + React.createElement(CustomComponent, { name: 'Lee Salminen', age: 23 }), + React.createElement(CustomComponent, { age: 28, position: 'Developer' }) + ), ReactableTestUtils.testNode()); + }); + + after(ReactableTestUtils.resetTestEnvironment); + + it('renders the table', function () { + expect($('table#table.table')).to.exist; + }); + + it('renders the column headers in the table', function () { + var headers = []; + $('thead th').each(function () { + headers.push($(this).text()); + }); + + expect(headers).to.eql(['Name', 'Age', 'Position']); + }); + + it('renders the first row with the correct data', function () { + ReactableTestUtils.expectRowText(0, ['Griffin Smith', '18', '']); + }); + + it('renders the second row with the correct data', function () { + ReactableTestUtils.expectRowText(1, ['Lee Salminen', '23', '']); + }); + + it('renders the third row with the correct data', function () { + ReactableTestUtils.expectRowText(2, ['', '28', 'Developer']); + }); + }); + describe('passing through HTML props', function () { describe('adding s with className to the
', function () { before(function () { diff --git a/lib/reactable/table.js b/lib/reactable/table.js index 24f036c5..888e0fd6 100644 --- a/lib/reactable/table.js +++ b/lib/reactable/table.js @@ -87,6 +87,9 @@ var Table = (function (_React$Component) { } }).bind(this)); } + }, { + key: 'childType', + value: function childType(child) {} }, { key: 'parseChildData', value: function parseChildData(props) { @@ -100,7 +103,17 @@ var Table = (function (_React$Component) { return; } - switch (child.type) { + var reactableDescendant = undefined; + var test = undefined; + + if ([_tfoot.Tfoot, _thead.Thead, _tr.Tr].indexOf(child.type) >= 0) { + reactableDescendant = child; + } else { + reactableDescendant = new child.type(child.props).render(); + test = true; + } + + switch (reactableDescendant.type) { case _tfoot.Tfoot: if (typeof tfoot !== 'undefined') { console.warn('You can only have one , but more than one was specified.' + 'Ignoring all but the last one'); @@ -108,9 +121,9 @@ var Table = (function (_React$Component) { tfoot = child; break; case _tr.Tr: - var childData = child.props.data || {}; + var childData = reactableDescendant.props.data || {}; - _react2['default'].Children.forEach(child.props.children, function (descendant) { + _react2['default'].Children.forEach(reactableDescendant.props.children, function (descendant) { // TODO /* if (descendant.type.ConvenienceConstructor === Td) { */ if (typeof descendant !== 'object' || descendant == null) { @@ -123,7 +136,7 @@ var Table = (function (_React$Component) { } else if (typeof descendant.props.children !== 'undefined') { value = descendant.props.children; } else { - console.warn('exports.Td specified without ' + 'a `data` property or children, ' + 'ignoring'); + console.warn('Td specified without ' + 'a `data` property or children, ' + 'ignoring'); return; } @@ -139,7 +152,7 @@ var Table = (function (_React$Component) { data.push({ data: childData, - props: (0, _libFilter_props_from.filterPropsFrom)(child.props), + props: (0, _libFilter_props_from.filterPropsFrom)(reactableDescendant.props), __reactableMeta: true }); break; diff --git a/src/reactable/table.jsx b/src/reactable/table.jsx index e69f1bd3..68f1f2c8 100644 --- a/src/reactable/table.jsx +++ b/src/reactable/table.jsx @@ -62,7 +62,17 @@ export class Table extends React.Component { return; } - switch (child.type) { + let reactableDescendant; + let test; + + if ([Tfoot, Thead, Tr].indexOf(child.type) >= 0) { + reactableDescendant = child + } else { + reactableDescendant = (new child.type(child.props)).render() + test = true + } + + switch (reactableDescendant.type) { case Tfoot: if (typeof(tfoot) !== 'undefined') { console.warn ('You can only have one , but more than one was specified.' + @@ -71,9 +81,9 @@ export class Table extends React.Component { tfoot = child; break; case Tr: - let childData = child.props.data || {}; + let childData = reactableDescendant.props.data || {}; - React.Children.forEach(child.props.children, function(descendant) { + React.Children.forEach(reactableDescendant.props.children, function(descendant) { // TODO /* if (descendant.type.ConvenienceConstructor === Td) { */ if ( @@ -89,7 +99,7 @@ export class Table extends React.Component { } else if (typeof(descendant.props.children) !== 'undefined') { value = descendant.props.children; } else { - console.warn('exports.Td specified without ' + + console.warn('Td specified without ' + 'a `data` property or children, ' + 'ignoring'); return; @@ -108,7 +118,7 @@ export class Table extends React.Component { data.push({ data: childData, - props: filterPropsFrom(child.props), + props: filterPropsFrom(reactableDescendant.props), __reactableMeta: true }); break; diff --git a/tests/reactable_test.jsx b/tests/reactable_test.jsx index d9b5fe19..4887766e 100644 --- a/tests/reactable_test.jsx +++ b/tests/reactable_test.jsx @@ -429,13 +429,14 @@ describe('Reactable', function() { render: function(){ return ( - {this.props.name} - {this.props.age} - {this.props.position} + {this.props.name || ''} + {this.props.age || ''} + {this.props.position || ''} ); } }); + React.render(