From b8a5c5ed3a13127985648ca0cd6c766cb9f61a37 Mon Sep 17 00:00:00 2001 From: Thomas Shafer Date: Wed, 12 Aug 2015 19:34:14 -0700 Subject: [PATCH 1/2] added failing test for rendering sub components --- tests/reactable_test.jsx | 57 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/tests/reactable_test.jsx b/tests/reactable_test.jsx index 45137eb4..185c8db2 100644 --- a/tests/reactable_test.jsx +++ b/tests/reactable_test.jsx @@ -417,6 +417,63 @@ describe('Reactable', function() { }); }); + 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(){ + return ( + + {this.props.name} + {this.props.age} + {this.props.position} + + ); + } + }); + React.render( + + + + + , + 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() { From a7a26046d888cc3744a9163ed1ee7f579f898066 Mon Sep 17 00:00:00 2001 From: Thomas Shafer Date: Thu, 13 Aug 2015 11:39:59 -0700 Subject: [PATCH 2/2] prototype solution to custom components Since react will not render child components until the parent component is rendered (exploratory hypotheis) We need to render the custom component first and then access the component. This uses a Component function of getData(). The getData function could/should be fast because after the render function all the data could be available via props or state I have not tested this with updating data from the custom component. Or if the custom component internally changes the data and they table needs to resort. --- src/reactable/table.jsx | 48 ++++++++++++++++++++++++++++++++++++---- tests/reactable_test.jsx | 7 ++++++ 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/reactable/table.jsx b/src/reactable/table.jsx index f7082d91..db0e41f9 100644 --- a/src/reactable/table.jsx +++ b/src/reactable/table.jsx @@ -12,6 +12,7 @@ export class Table extends React.Component { super(props); this.state = { + parsedCustomComponents: false, currentPage: 0, currentSort: { column: null, @@ -52,7 +53,7 @@ export class Table extends React.Component { } parseChildData(props) { - let data = [], tfoot; + let data = [], tfoot, customComponentsCount = 0; // Transform any children back to a data array if (typeof(props.children) !== 'undefined') { @@ -111,19 +112,26 @@ export class Table extends React.Component { __reactableMeta: true }); break; + default: + // Don't know if there are other acceptable types + // that should be dismissed + // console.log("Table, got custom component", child.type) + customComponentsCount++; + break; } }.bind(this)); } - return { data, tfoot }; + return { data, tfoot, customComponentsCount }; } initialize(props) { this.data = props.data || []; - let { data, tfoot } = this.parseChildData(props); + let { data, tfoot, customComponentsCount } = this.parseChildData(props); this.data = this.data.concat(data); this.tfoot = tfoot; + this.customComponentsCount = customComponentsCount; this.initializeSorts(props); } @@ -205,6 +213,26 @@ export class Table extends React.Component { this.sortByCurrentSort(); } + componentDidMount() { + for (var i = 0; i < this.customComponentsCount; i++) { + let child = this.refs['child-'+i], + childData = child.getData(), + childDataToPush = {}; + for (var key in childData){ + childDataToPush[key] = { + value: childData[key], + __reactableMeta: true + }; + } + this.data.push({ + data: childDataToPush, + props: filterPropsFrom(child.props), + __reactableMeta: true + }); + }; + this.setState({parsedCustomComponents: true}); + } + componentWillReceiveProps(nextProps) { this.initialize(nextProps); this.updateCurrentSort(nextProps.sortBy); @@ -296,8 +324,20 @@ export class Table extends React.Component { this.setState({ currentSort: currentSort }); this.sortByCurrentSort(); } - + renderUnparsedDataTable() { + // http://www.mattzabriskie.com/blog/react-referencing-dynamic-children + let index = 0; + let children = React.Children.map(this.props.children, function (child) { + return React.addons.cloneWithProps(child, {ref: 'child-' + (index++) }); + }); + + return
{children}
; + } render() { + if (!this.state.parsedCustomComponents && this.customComponentsCount > 0){ + return this.renderUnparsedDataTable(); + } + let children = []; let columns; let userColumnsSpecified = false; diff --git a/tests/reactable_test.jsx b/tests/reactable_test.jsx index 185c8db2..54e0b557 100644 --- a/tests/reactable_test.jsx +++ b/tests/reactable_test.jsx @@ -426,6 +426,13 @@ describe('Reactable', function() { age: React.PropTypes.number, position: React.PropTypes.string }, + getData: function(){ + return { + Name: this.props.name, + Age: this.props.age, + Position: this.props.position, + } + }, render: function(){ return (