How to use rowSpan? #2233
-
I made a minimal repro of my original code. Here it is in HTML: <!DOCTYPE html>
<html>
<head>
<style>
table, th, td {
text-align: center;
border: 1px dashed lightpink;
color: navy;
}
</style>
</head>
<body>
<table>
<tr>
<th>Actor</th>
<th>Movies</th>
</tr>
<tr>
<td rowspan="4">Johnny Depp</td>
<td>Pirates of the Carribean 1</td>
</tr>
<tr>
<td>Pirates of the Carribean 2</td>
</tr>
<tr>
<td>Pirates of the Carribean 3</td>
</tr>
<tr>
<td>Pirates of the Carribean 4</td>
</tr>
</table>
</body>
</html> The output looks like: So I tried implementing it in CodeSandBox. Following is the code: import * as React from "react";
import { useTable } from "react-table";
const borderStyle = {
border: "1px dashed navy"
};
export default function App() {
const data = React.useMemo(
() => [
{
actor: "Johnny Depp",
movies: [
{
name: "Pirates of the Carribean 1"
},
{
name: "Pirates of the Carribean 2"
},
{
name: "Pirates of the Carribean 3"
},
{
name: "Pirates of the Carribean 4"
}
]
}
],
[]
);
const columns = React.useMemo(
() => [
{
Header: "Actor",
accessor: "actor",
enableRowSpan: true
},
{
Header: "Movies",
accessor: (row, index) => {
console.log({ row });
return row.movies.map(movie => movie.name);
}
}
],
[]
);
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow
} = useTable({ columns, data });
return (
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()} style={borderStyle}>
{column.render("Header")}
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row, i) => {
prepareRow(row);
if (i == 0) {
console.log({ row });
}
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell, j) => {
if (i == 0 && j < 2) {
console.log({ cell, i, j });
}
return (
<td
rowSpan={cell.rowSpan}
{...cell.getCellProps()}
style={borderStyle}
>
{cell.render("Cell")}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
);
} Here's the direct link to it: https://codesandbox.io/s/modest-sanderson-z0keq?file=/src/App.tsx It looks like: I want movie names to be one below the other but can't seem to figure it out 🤔 I want it to look like the HTML. The data shouldn't change as my original use-case fetches from an API. How do I do it? |
Beta Was this translation helpful? Give feedback.
Replies: 9 comments 25 replies
-
There is no rowspan hook included in react-table currently. So while you are setting rowSpanEnabled on the header and referencing cell.rowSpan, you aren't ever setting cell.rowSpan or checking rowSpanEnabled again. |
Beta Was this translation helpful? Give feedback.
-
@liberza I got that. I left that part out purposely because Idk how to display the movie names row by row. My movie list is an array of objects so how will I display it beside actor name? So it looks like:
Once I fix that, I can totally see myself copying your Codesandbox ;) |
Beta Was this translation helpful? Give feedback.
-
Okay made it work. Guess I just had to flatten the data. It was as easy as just copying & pasting your code. Here's the working solution: import * as React from "react";
import { useTable } from "react-table";
type Data = {
actor: string;
movie: string;
};
const borderStyle = {
border: "1px solid gray",
padding: "8px 10px"
};
function useInstance(instance) {
const { allColumns } = instance;
let rowSpanHeaders = [];
allColumns.forEach((column, i) => {
const { id, enableRowSpan } = column;
if (enableRowSpan !== undefined) {
rowSpanHeaders = [
...rowSpanHeaders,
{ id, topCellValue: null, topCellIndex: 0 }
];
}
});
Object.assign(instance, { rowSpanHeaders });
}
export default function App() {
const origData = [
{
actor: "Johnny Depp",
movies: [
{
name: "Pirates of the Carribean 1"
},
{
name: "Pirates of the Carribean 2"
},
{
name: "Pirates of the Carribean 3"
},
{
name: "Pirates of the Carribean 4"
}
]
}
];
const newData: Array<Data> = [];
origData.forEach(actorObj => {
actorObj.movies.forEach(movie => {
newData.push({
actor: actorObj.actor,
movie: movie.name
});
});
});
const data = React.useMemo(() => newData, []);
const columns = React.useMemo(
() => [
{
Header: "Actor",
accessor: "actor",
enableRowSpan: true
},
{
Header: "Movies",
accessor: "movie"
}
],
[]
);
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
rowSpanHeaders
} = useTable({ columns, data }, hooks => {
hooks.useInstance.push(useInstance);
});
return (
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()} style={borderStyle}>
{column.render("Header")}
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row, i) => {
prepareRow(row);
for (let j = 0; j < row.allCells.length; j++) {
let cell = row.allCells[j];
let rowSpanHeader = rowSpanHeaders.find(
x => x.id === cell.column.id
);
if (rowSpanHeader !== undefined) {
if (
rowSpanHeader.topCellValue === null ||
rowSpanHeader.topCellValue !== cell.value
) {
cell.isRowSpanned = false;
rowSpanHeader.topCellValue = cell.value;
rowSpanHeader.topCellIndex = i;
cell.rowSpan = 1;
} else {
rows[rowSpanHeader.topCellIndex].allCells[j].rowSpan++;
cell.isRowSpanned = true;
}
}
}
return null;
})}
{rows.map(row => {
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
if (cell.isRowSpanned) return null;
else
return (
<td
style={borderStyle}
rowSpan={cell.rowSpan}
{...cell.getCellProps()}
>
{cell.render("Cell")}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
);
} And here's the link to Codesandbox 👉 https://codesandbox.io/s/flattening-row-with-react-table-prkqb?file=/src/App.tsx Thank you @liberza 🙌 |
Beta Was this translation helpful? Give feedback.
-
@liberza I found 1 problem with your solution. Guess it might be an edge-case. But here's the problem. I have 2 columns that I have to As the 2nd one is a Here's a visual:
So the The problem comes while spanning Let me know if you have any solutions in this regard? Also, keep this use-case in mind while making the plugin, I guess it'll be a common one. Just a hunch :) |
Beta Was this translation helpful? Give feedback.
-
Is there any way by which we can have row span on the table header, like the one below |
Beta Was this translation helpful? Give feedback.
-
I was wondering if there's a way to use |
Beta Was this translation helpful? Give feedback.
-
@deadcoder0904 Is there a way to achieve this for colspan ? |
Beta Was this translation helpful? Give feedback.
-
What about the support for the same in v8? Is there any roadmap for this? |
Beta Was this translation helpful? Give feedback.
Okay made it work. Guess I just had to flatten the data. It was as easy as just copying & pasting your code. Here's the working solution: