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

Allow specifying table rows in custom components #196

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions build/reactable.js
Original file line number Diff line number Diff line change
Expand Up @@ -1046,17 +1046,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, child._context).render();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this works in react 0.14.

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

describe('adding <CustomComponents>s to the <Table>', function () {
context('passing through props', 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']);
});
});

context('passing through context', function () {
before(function () {
var RowComponent = React.createClass({
displayName: 'CustomComponent',
contextTypes: { test: 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: 'Test' },
this.context.test || ''
)
);
}
});

var TableComponent = React.createClass({
displayName: 'TableComponent',
childContextTypes: { test: React.PropTypes.string },
getChildContext: function getChildContext() {
return { test: 'foobar' };
},
render: function render() {
return React.createElement(
Reactable.Table,
{ className: 'table', id: 'table' },
React.createElement(RowComponent, { name: 'Griffin Smith' }),
React.createElement(RowComponent, { name: 'Lee Salminen' })
);
}
});

React.render(React.createElement(TableComponent, null), ReactableTestUtils.testNode());
});

after(ReactableTestUtils.resetTestEnvironment);

it('renders the table', function () {
expect($('table#table.table')).to.exist;
});

it('renders the first row with the correct data', function () {
ReactableTestUtils.expectRowText(0, ['Griffin Smith', 'foobar']);
});

it('renders the second row with the correct data', function () {
ReactableTestUtils.expectRowText(1, ['Lee Salminen', 'foobar']);
});
});
});

describe('passing through HTML props', function () {
describe('adding <Tr>s with className to the <Table>', function () {
before(function () {
Expand Down
20 changes: 15 additions & 5 deletions lib/reactable/table.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,17 +100,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, child._context).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 +133,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 +149,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, child._context)).render()
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
109 changes: 109 additions & 0 deletions tests/reactable_test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,115 @@ describe('Reactable', function() {
});
});

describe('adding <CustomComponents>s to the <Table>', function() {
context('passing through props', 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 (
<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.Tr>
);
}
});

React.render(
<Reactable.Table className="table" id="table">
<CustomComponent name='Griffin Smith' age={18} />
<CustomComponent name='Lee Salminen' age={23} />
<CustomComponent age={28} position='Developer' />
</Reactable.Table>,
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']);
});
});

context('passing through context', function() {
before(function() {
let RowComponent = React.createClass({
displayName: 'CustomComponent',
contextTypes: { test: React.PropTypes.string },
render: function(){
return (
<Reactable.Tr>
<Reactable.Td column="Name">{this.props.name || ''}</Reactable.Td>
<Reactable.Td column="Test">{this.context.test || ''}</Reactable.Td>
</Reactable.Tr>
);
}
});

let TableComponent = React.createClass({
displayName: 'TableComponent',
childContextTypes: { test: React.PropTypes.string },
getChildContext: function() {
return { test: 'foobar' };
},
render: function() {
return (
<Reactable.Table className="table" id="table">
<RowComponent name='Griffin Smith' />
<RowComponent name='Lee Salminen' />
</Reactable.Table>
);
}
});

React.render(<TableComponent/>, ReactableTestUtils.testNode());
});

after(ReactableTestUtils.resetTestEnvironment);

it('renders the table', function() {
expect($('table#table.table')).to.exist;
});

it('renders the first row with the correct data', function() {
ReactableTestUtils.expectRowText(0, ['Griffin Smith', 'foobar']);
});

it('renders the second row with the correct data', function() {
ReactableTestUtils.expectRowText(1, ['Lee Salminen', 'foobar']);
});
});
});

describe('passing through HTML props', function() {
describe('adding <Tr>s with className to the <Table>', function() {
before(function() {
Expand Down