Bram Wesselink
Bram Wesselink

Reputation: 147

React HTML table

I am currently trying to make a HTML table work in React, but something isn't going the way it should. I do get a render output but with the error of: <tr> cannot appear as a child of <div>.

I tried to find it online, but the technique I am using doesn't seem to be used that often, so if I am doing that wrong, please enlighten me.
Thank you in advance!

getTableContent = (arr) => {
    let result = [];
    arr.forEach(function (item, i) {
        result.push(
            <table key={item.productType}>
                <thead>{item.productType}</thead>
                <tbody>
                    {item.contents.forEach(function (nextItem, j) {
                        result.push(
                            <tr key={nextItem.type}>
                                <td>{nextItem.type}</td>
                                <td>{nextItem.count}</td>
                            </tr>
                        )
                    })}
                </tbody>
            </table>
            );
    });
    return result;
};

render() {
    return (
            <div>{this.getTableContent(productSpecification)}</div>
    );
}

The data looks as follows:

const productSpecification = [
    {
        productType: "abc", contents: [
            {type: "abc", count: 231},
            {type: "abc", count: 56},
            {type: "abc", count: 54},
            {type: "abc", count: 544},
            {type: "abc", count: 54},
            {type: "abc", count: 564},
            {type: "abc", count: 4},
            {type: "abc", count: 4564},
            {type: "abc", count: 4531},
            {type: "abc", count: 234},
            {type: "abc", count: 57},
            {type: "abc", count: 7}
        ]
    }
];

Upvotes: 5

Views: 26219

Answers (3)

Al.G.
Al.G.

Reputation: 4387

This is supposed to return tr rows:

{item.contents.forEach(function (nextItem, j) {
    result.push(
        <tr key={nextItem.type}>
            <td>{nextItem.type}</td>
            <td>{nextItem.count}</td>
        </tr>
    )
})}

But in fact it modifies the result variable, pushing the trs to it instead of returning them. This causes the result variable to be full of both tables and trs. You should return the trs in map, not push them to result in a forEach:

{item.contents.map(function (nextItem, j) {
    return (
        <tr key={nextItem.type}>
            <td>{nextItem.type}</td>
            <td>{nextItem.count}</td>
        </tr>
    )
})}

Upvotes: 0

Midhun G S
Midhun G S

Reputation: 957

instead of pushing to array you can try return jsx from function Try this.

getTableContent = (arr) => {
    const iterateItem = (item) => {
       return item.map(function (nextItem, j) {
         return (
            <tr key={nextItem.type}>
               <td>{nextItem.type}</td>
               <td>{nextItem.count}</td>
            </tr>
         );
       })
    }
    return arr.map(function (item, i) {
        return (
            <table key={item.productType}>
            <thead>{item.productType}</thead>
                <tbody>
                    {iterateItem(item.contents)}
                </tbody>
            </table>
        );
    });
};

render() {
    return (
            <div>{this.getTableContent(productSpecification)}</div>
    );
}

Upvotes: 6

S. Mac
S. Mac

Reputation: 1

You need to add opening and closing <tbody> tags, like this:

<table>
<tbody>
<tr><td>1</td></tr>
<tr><td>2</td></tr>
...
</tbody>
</table>

Upvotes: 0

Related Questions