Skip to content
This repository has been archived by the owner on Jan 15, 2022. It is now read-only.

Commit

Permalink
Allow specifying table rows in custom components
Browse files Browse the repository at this point in the history
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 `<Tr>`
  • Loading branch information
glittershark committed Sep 30, 2015
1 parent d19826d commit 4abe39c
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 18 deletions.
23 changes: 18 additions & 5 deletions build/reactable.js
Original file line number Diff line number Diff line change
Expand Up @@ -1033,6 +1033,9 @@ window.React["default"] = window.React;
}
}).bind(this));
}
}, {
key: 'childType',
value: function childType(child) {}
}, {
key: 'parseChildData',
value: function parseChildData(props) {
Expand All @@ -1046,17 +1049,27 @@ 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 <Tfoot>, but more than one was specified.' + 'Ignoring all but the last one');
}
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) {
Expand All @@ -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;
}

Expand All @@ -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;
Expand Down
69 changes: 69 additions & 0 deletions build/tests/reactable_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,75 @@
});
});

describe('adding <CustomComponents>s to the <Table>', 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 <Tr>s with className to the <Table>', function () {
before(function () {
Expand Down
23 changes: 18 additions & 5 deletions lib/reactable/table.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ var Table = (function (_React$Component) {
}
}).bind(this));
}
}, {
key: 'childType',
value: function childType(child) {}
}, {
key: 'parseChildData',
value: function parseChildData(props) {
Expand All @@ -100,17 +103,27 @@ 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 <Tfoot>, but more than one was specified.' + 'Ignoring all but the last one');
}
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) {
Expand All @@ -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;
}

Expand All @@ -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;
Expand Down
20 changes: 15 additions & 5 deletions src/reactable/table.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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()

This comment has been minimized.

Copy link
@trshafer

trshafer Sep 30, 2015

This appears to not pass in the React context.

This comment has been minimized.

Copy link
@trshafer

trshafer Sep 30, 2015

I'm currently investigating. I think if I explicitly pass in my context via props I'll be ok.

This comment has been minimized.

Copy link
@trshafer

trshafer Sep 30, 2015

Yeah it's not playing nicely with react-router. Some of my Td's contain links to go to the individual page for that row item. I've tried manually passing in context via props to my child Tr's. I've tried passing in the context to the Table. I've tried specifying getChildContext to include the router. I've tried changing it to (new child.type(child.props, child.props.context)).render() when I pass in the context props. This is the error that comes up: https://gist.github.com/jimfb/0eb6e61f300a8c1b2ce7 . The owner is the table (I think, it might not actually have an owner), and the parent is my component which holds the Table. They differ and it's currently taking the owner context.

test = true
}

switch (reactableDescendant.type) {
case Tfoot:
if (typeof(tfoot) !== 'undefined') {
console.warn ('You can only have one <Tfoot>, but more than one was specified.' +
Expand All @@ -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 (
Expand All @@ -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;
Expand All @@ -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;
Expand Down
7 changes: 4 additions & 3 deletions tests/reactable_test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -429,13 +429,14 @@ describe('Reactable', function() {
render: function(){
return (
<Reactable.Tr>
<Reactable.Td column="Name">{this.props.name}</Reactable.Td>
<Reactable.Td column="Age">{this.props.age}</Reactable.Td>
<Reactable.Td column="Position">{this.props.position}</Reactable.Td>
<Reactable.Td column="Name">{this.props.name || ''}</Reactable.Td>
<Reactable.Td column="Age">{this.props.age || ''}</Reactable.Td>
<Reactable.Td column="Position">{this.props.position || ''}</Reactable.Td>
</Reactable.Tr>
);
}
});

React.render(
<Reactable.Table className="table" id="table">
<CustomComponent name='Griffin Smith' age={18} />
Expand Down

0 comments on commit 4abe39c

Please sign in to comment.