fix(data-table): handle dynamic headers gracefully

This commit is contained in:
Eric Liu 2025-08-28 18:54:47 -07:00
commit 6ed7881233
2 changed files with 94 additions and 7 deletions

View file

@ -263,12 +263,13 @@
expanded = expandedRowIds.length === expandableRowIds.length;
}
$: if (radio || batchSelection) selectable = true;
$: headerKeys = headers.map(({ key }) => key);
$: tableCellsByRowId = rows.reduce((rows, row) => {
rows[row.id] = headerKeys.map((key, index) => ({
key,
value: resolvePath(row, key),
display: headers[index].display,
rows[row.id] = headers.map((header, index) => ({
key: header.key || `key-${index}`,
value: header.key ? resolvePath(row, header.key) : undefined,
display: header.display,
empty: header.empty,
columnMenu: header.columnMenu,
}));
return rows;
}, {});
@ -557,8 +558,8 @@
</td>
{/if}
{#each tableCellsByRowId[row.id] as cell, j (cell.key)}
{#if headers[j].empty}
<td class:bx--table-column-menu={headers[j].columnMenu}>
{#if cell.empty}
<td class:bx--table-column-menu={cell.columnMenu}>
<slot name="cell" {row} {cell} rowIndex={i} cellIndex={j}>
{cell.display ? cell.display(cell.value, row) : cell.value}
</slot>

View file

@ -772,4 +772,90 @@ describe("DataTable", () => {
expect.any(Object),
);
});
it("should handle changing number of headers without crashing", async () => {
const rows = [
{
id: "a",
name: "Load Balancer 3",
protocol: "HTTP",
port: 3000,
rule: "Round robin",
},
{
id: "b",
name: "Load Balancer 1",
protocol: "HTTP",
port: 443,
rule: "Round robin",
},
];
const headers5 = [
{ key: "name", value: "Name" },
{ key: "protocol", value: "Protocol" },
{ key: "port", value: "Port" },
{ key: "rule", value: "Rule" },
{ key: "actions", value: "Actions" },
];
const headers3 = [
{ key: "name", value: "Name" },
{ key: "protocol", value: "Protocol" },
{ key: "port", value: "Port" },
];
const { component, rerender } = render(DataTable, {
props: {
rows,
headers: headers5,
},
});
// First render with 5 headers
expect(component).toBeTruthy();
// Change to 3 headers - this should not crash
await rerender({
rows,
headers: headers3,
});
expect(component).toBeTruthy();
// Change back to 5 headers - this should not crash
await rerender({
rows,
headers: headers5,
});
expect(component).toBeTruthy();
});
it("should handle empty headers correctly", async () => {
const rows = [
{
id: "a",
name: "Load Balancer 3",
protocol: "HTTP",
port: 3000,
rule: "Round robin",
},
];
const headersWithEmpty = [
{ key: "name", value: "Name" },
{ key: "protocol", value: "Protocol" },
{ key: "actions", value: "", empty: true, columnMenu: true },
];
const { component } = render(DataTable, {
props: {
rows,
headers: headersWithEmpty,
},
});
expect(component).toBeTruthy();
});
});