danialsaufi
danialsaufi

Reputation: 69

Implementing checkbox using TanStack table in Solidjs

I'm struggling to get the checkbox working using TanStack in Solidjs. The docs doesn't have much information about creating a checkbox column which is why i followed the TanStack React Table Examples and some of the Solidjs Table Examples. The checkbox would not update and i am assuming this has something to do with Solidjs reactivity. Here props is not updating since i tried to console.log it and it only ran once which was when the component rendered.


const checkbox = {
accessorKey: "checkbox",
        header: (props) => (
            <Checkbox
                {...{
                    checked: props.table.getIsAllRowsSelected(),
                    indeterminate: props.table.getIsSomeRowsSelected(),
                    onChange: props.table.getToggleAllRowsSelectedHandler(),
                }}
            />
        ),
        cell: (props) => {


            return (
                <Checkbox
                    {...{
                        checked: props.row.getIsSelected(),
                        disabled: !props.row.getCanSelect(),
                        onChange: props.row.getToggleSelectedHandler(),
                    }}
                />
            );
        },
    };

If i do it without TanStack, it would look something like this but it defeats the purpose of using TanStack

cell: () => {
            const [isSelected , setIsSelected] = createSignal(false)

            const toggleSelected = (event , checked) => {
                setIsSelected(checked)
            }

            return (
                <Checkbox
                    {...{
                        checked: isSelected(),
                        onChange: toggleSelected,
                    }}
                />
            );
        },

*** Update 1: Here is the whole code of creating the table


const generateColumns = (columns) => {
    const result = columns.map((value) => {
        return {
            accessorKey: value,
        };
    });

    return result;
};

const DataTable = (props) => {
    const [rowSelection, setRowSelection] = createSignal({});

    const checkbox = {
        accessorKey: "checkbox",
        header: (props) => (
            <Checkbox
                {...{
                    checked: props.table.getIsAllRowsSelected,
                    indeterminate: props.table.getIsSomeRowsSelected,
                    onChange: props.table.getToggleAllRowsSelectedHandler,
                }}
            />
        ),
        cell: () => {
            const [isSelected , setIsSelected] = createSignal(false)

            const toggleSelected = (event , checked) => {
                setIsSelected(checked)
            }

            return (
                <Checkbox
                    {...{
                        checked: isSelected(),
                        onChange: toggleSelected,
                    }}
                />
            );
        },
    };

    const columns = [checkbox, ...generateColumns(props.columns)];

    const table = createSolidTable({
        get data() {
            return props.data;
        },
        columns: columns,
        state: {
            get rowSelection() {
                return rowSelection();
            },
        },
        onRowSelectionChange: setRowSelection,
        getCoreRowModel: getCoreRowModel(),
    });

    return (
        <TableContainer component={Paper}>
            <Table>
                <TableHead>
                    <For each={table.getHeaderGroups()}>
                        {(headerGroup) => (
                            <TableRow>
                                <For each={headerGroup.headers}>
                                    {(header) => (
                                        <TableCell>
                                            {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
                                        </TableCell>
                                    )}
                                </For>
                            </TableRow>
                        )}
                    </For>
                </TableHead>
                <TableBody>
                    <For each={table.getRowModel().rows}>
                        {(row) => (
                            <TableRow>
                                <For each={row.getVisibleCells()}>
                                    {(cell) => <TableCell>{flexRender(cell.column.columnDef.cell, cell.getContext())}</TableCell>}
                                </For>
                            </TableRow>
                        )}
                    </For>
                </TableBody>
            </Table>
        </TableContainer>
    );
};

Upvotes: 0

Views: 1332

Answers (1)

axelra82
axelra82

Reputation: 537

I was in a similar spot, coming from the React version of Tanstack Table.

Having looked at your code I was able to make mine work with some minor modifications based on your implementation.

Hopefully this can help you finalize a working solution as well.

Here's the code for my SolidJS table component with working select column:

export const Table: Component<TableData> & TableSubComponentsInterface = (props) => {
    const merged = mergeProps({
        enableRowSelection: () => true,
    }, props);

    const isWorking = useWorking();

    const [sorting, sortingSet] = createSignal<ColumnSort[]>();
    const [rowSelection, rowSelectionSet] = createSignal<RowSelectionState>();
    const [columnFilters, setColumnFilters] = createSignal<ColumnFilter[]>();

    const tableOptions = {
        get data() {
            return merged.columnData ?? [];
        },
        // eslint-disable-next-line solid/reactivity
        columns: merged.columns ?? [],
        state: {
            get rowSelection() {
                return rowSelection();
            },
            get sorting() {
                return sorting();
            },
            get columnFilters() {
                return columnFilters();
            },
        },
        enableRowSelection: (row: TanstackRow<Record<string, unknown>>) => merged.enableRowSelection(row),
        onColumnFiltersChange: setColumnFilters,
        getFilteredRowModel: getFilteredRowModel(),
        getCoreRowModel: getCoreRowModel(),
        getSortedRowModel: getSortedRowModel(),
        onSortingChange: sortingSet,
        onRowSelectionChange: rowSelectionSet,
    };

    const solidTable = createSolidTable(tableOptions);

    return (
            <section class="no-scrollbar table-rounded-md max-w-xl7 w-full overflow-auto rounded-md border border-gray-200 bg-white drop-shadow-sm">
                <table class="w-full">
                    <thead>
                        <For each={solidTable.getHeaderGroups()}>{(headerGroup) => (
                            <tr

                                class="items-center border-b border-b-gray-200 text-left font-semibold capitalize"
                            >
                                <For each={headerGroup.headers}>{(header) => (
                                    <th colSpan={header.colSpan}>
                                        <Show when={!header.isPlaceholder}>
                                            <div
                                                class={`${header.column.getCanSort() ? "cursor-pointer select-none" : ""} flex items-center gap-x-2 p-4`}
                                                onClick={header.column.getToggleSortingHandler()}
                                            >
                                                {flexRender(header.column.columnDef.header, header.getContext())}
                                                {{
                                                    asc: <ExpandLessIcon size={Size.XS} />,
                                                    desc: <ExpandMoreIcon size={Size.XS} />,
                                                }[header.column.getIsSorted() as string]
                                                    ?? (header.column.getCanSort() ? (
                                                        <UnfoldMoreIcon size={Size.SM} />
                                                    ) : null)}
                                            </div>
                                        </Show>
                                    </th>
                                )
                                }</For>
                            </tr>
                        )}</For>
                    </thead>
                    <tbody>
                        <For each={solidTable.getRowModel().rows}>{(row) => (
                            <tr class=" border-b border-b-gray-200 hover:bg-gray-50">
                                <For each={row.getVisibleCells()}>{(cell) => (
                                    <td class="p-4">
                                        {flexRender(cell.column.columnDef.cell, cell.getContext())}
                                    </td>
                                )}</For>
                            </tr>
                        )}</For>
                    </tbody>
                </table>
            </section>
    );
};

Excerpt usage:

import { createColumnHelper } from "@tanstack/solid-table";

const TableUsageComponent = () => {
const columnHelper = createColumnHelper<Record<string, unknown>>();
const columns = [
    columnHelper.accessor("id", selectColumn), // This would be the select column
    // Other required columns for your use case.
]

// In case you have fetching/loading logic.
const isFetching = false;

// Data for columns should go here.
const columnData = [
  {
    key1: "some value",
    key2: "some value 2",
    // ...
  }
];

return (
    <Show when={!isFetching} fallback={<TableLoader />}>
        <Table
            columnData={columnData}
            columns={columns}
        />
    </Show>
);
}

export default TableUsageComponent;

The selectColumn column helper variable (where Checkbox component is a custom component in this case. You might have to accommodate any properties or parameters for you checkbox component):

import { Row as TanstackRow, Table as TanstackTable } from "@tanstack/solid-table";
import { Show } from "solid-js";

import { Checkbox } from "../form";

export const selectColumn = {
    id: "select",
    header: (props: { table: TanstackTable<Record<string, unknown>>; }) => (
        <Checkbox
            {...{
                checked: props.table.getIsAllRowsSelected(),
                indeterminate: !props.table.getIsAllRowsSelected() && props.table.getIsSomeRowsSelected(),
                onChange: props.table.getToggleAllRowsSelectedHandler(),
            }}
        />
    ),
    cell: (props: { row: TanstackRow<Record<string, unknown>>; }) => (
        <Show when={props.row.getCanSelect()}>
            <div class="px-1">
                <Checkbox
                    {...{
                        checked: props.row.getIsSelected(),
                        indeterminate: props.row.getIsSomeSelected(),
                        onChange: props.row.getToggleSelectedHandler(),
                    }}
                />
            </div>
        </Show>
    ),
    enableSorting: false,
};

Upvotes: 1

Related Questions