reactjsnode.jsnext.jsnextui

Dynamic table, display nested property in TableCell from array of objects


I have an array tracks of type Track[]. I need to display them in a HeroUI/NextUI table dynamically. The example uses getKeyValue, which is a function in the HeroUI library, to dynamically retrieve the value of each cell. However, some of the properties I need to access with getKeyValue are nested. Is there any way to access properties such as album.name?

// imports ...
// nextjs page component...

interface Album {
  name: String;
}

interface Track {
  name: String;
  album: Album;
}

const tableColumns = [
  { label: "Title", key: "name" },
  { label: "Album", key: "album.name" },
];

const [tracks, setTracks] = useState<Track[]>();

// fetch tracks ...

return (
  <Table className="table-auto">
    <TableHeader columns={tableColumns}>
      {(column) => (
        <TableColumn key={column.key}>{column.label}</TableColumn>
      )}
    </TableHeader>
    <TableBody items={tracks}>
      {(item) => (
        <TableRow key={item.id}>
          {(columnKey) => (
            <TableCell>{getKeyValue(item, columnKey)}</TableCell>
          )}
        </TableRow>
      )}
    </TableBody>
  </Table>
);

Solution

  • Instead of using getKeyValue from heroui, you can create a custom function for this specific use case

    "use client";
    
    import { Table, TableHeader, TableColumn, TableBody, TableRow, TableCell } from "@heroui/table";
    
    function getKeyValue(item: any, columnKey: string | number): string | number {
        if (typeof columnKey === 'number') {
            return item[columnKey];
        }
    
        if (columnKey.includes('.')) {
            const [firstPart, secondPart] = columnKey.split('.');
            return item[firstPart][secondPart];
        } else {
            return item[columnKey];
        }
    }
    
    interface Album {
        name: String;
    }
    
    interface Track {
        key: string;
        name: String;
        album: Album;
    }
    
    const rows: Track[] = [
        {
            key: "1",
            name: "Track 1",
            album: {
                name: 'Album 1'
            }
        },
        {
            key: "2",
            name: "Track 2",
            album: {
                name: 'Album 2'
            }
        },
        {
            key: "3",
            name: "Track 3",
            album: {
                name: 'Album 3'
            }
        },
    ];
    
    const columns: { key: string; label: string }[] = [
        {
            key: "key",
            label: "ID",
        },
        {
            key: "name",
            label: "Track",
        },
        {
            key: "album.name",
            label: "Album",
        }
    ];
    
    export default function App() {
        return (
            <Table aria-label="Example table with dynamic content">
                <TableHeader columns={columns}>
                    {(column) => <TableColumn key={column.key}>{column.label}</TableColumn>}
                </TableHeader>
                <TableBody items={rows}>
                    {(item) => (
                        <TableRow key={item.key}>
                            {(columnKey) => <TableCell>{getKeyValue(item, String(columnKey))}</TableCell>}
                        </TableRow>
                    )}
                </TableBody>
            </Table>
        );
    }