Martin
Martin

Reputation: 1578

Tanstack Table React row selection not working

I have a working version of Tanstack Table in React.js that lets me drag and drop to re-order rows one at a time. https://codesandbox.io/p/sandbox/table-test-forked-7htfr5?workspaceId=ws_F2QxELJDBKDDSAxdPEPbQt

I am trying to add the row selection feature they have demonstrated online here: https://tanstack.com/table/v8/docs/framework/react/examples/row-selection

I have tried my own version of implementing the row-selection logic into my first link working drag and drop codesandbox, but the behavior is wrong, as the user is only allowed to drag and drop one row, before the feature becomes broken and stops working: https://codesandbox.io/p/sandbox/table-test-forked-t8xtqr?workspaceId=ws_F2QxELJDBKDDSAxdPEPbQt

Can someone help me add the checkmark row selection row to my working drag and drop table below? Thanks App.js:

import "./styles.css";
import Table from "./Table.js"; // Adjust the path as necessary
import { arrayMove } from "@dnd-kit/sortable";
import { useState } from "react";

export default function App() {
  const [testData, setTestData] = useState([
    { id: "a1", fileName: "Test Audio 1", duration: "2:30" },
    { id: "a2", fileName: "Test Audio 2", duration: "3:45" },
    { id: "a3", fileName: "Test Audio 3", duration: "4:15" },
  ]);

  const testColumns = [
    { accessorKey: "draggable", header: "Drag" },
    { accessorKey: "fileName", header: "File Name" },
    { accessorKey: "duration", header: "Duration" },
  ];

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <Table
        data={testData}
        setData={(oldData, active, over) => {
          const oldIndex = oldData.findIndex((row) => row.id === active.id);
          const newIndex = oldData.findIndex((row) => row.id === over.id);

          if (oldIndex !== -1 && newIndex !== -1) {
            const newData = arrayMove(oldData, oldIndex, newIndex);
            setTestData(newData);
          }
        }}
        columns={testColumns}
      />
    </div>
  );
}

Table.js:

// https://tanstack.com/table/v8/docs/framework/react/examples/row-selection

import React from "react";
import {
  ColumnDef,
  getCoreRowModel,
  useReactTable,
  flexRender,
} from "@tanstack/react-table";
import { DndContext, closestCenter } from "@dnd-kit/core";
import {
  arrayMove,
  SortableContext,
  verticalListSortingStrategy,
} from "@dnd-kit/sortable";
import { useSortable } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import styles from "./Table.module.css";

// Drag handle for rows
function DragHandle({ row }) {
  const { attributes, listeners } = useSortable({ id: row.original.id });

  return (
    <button
      {...attributes}
      {...listeners}
      className={styles.dragHandle}
      title="Drag to reorder"
    >
      🟰
    </button>
  );
}

// Row Component
function Row({ row }) {
  const { attributes, listeners, setNodeRef, transform, transition } =
    useSortable({
      id: row.original.id,
    });

  const style = {
    transform: CSS.Transform.toString(transform),
    transition,
  };

  return (
    <tr
      ref={setNodeRef}
      style={style}
      {...attributes}
      {...listeners}
      className={styles.row}
    >
      {row.getVisibleCells().map((cell, index) => (
        <td key={cell.id} className={styles.cell}>
          {index === 0 ? <DragHandle row={row} /> : null}
          {flexRender(cell.column.columnDef.cell, cell.getContext())}
        </td>
      ))}
    </tr>
  );
}

// Table Component
function Table({ data, setData, columns }) {
  const tableColumns = React.useMemo(() => [...columns], [columns]);

  const table = useReactTable({
    data,
    columns: tableColumns,
    getCoreRowModel: getCoreRowModel(),
  });

  const handleDragEnd = (event) => {
    const { active, over } = event;

    if (!active?.id || !over?.id || active.id === over.id) {
      return;
    }

    setData(data, active, over);
  };

  return (
    <DndContext collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
      <SortableContext
        items={data.map((row) => row.id)}
        strategy={verticalListSortingStrategy}
      >
        <table className={styles.table}>
          <thead>
            {table.getHeaderGroups().map((headerGroup) => (
              <tr key={headerGroup.id} className={styles.headerRow}>
                {headerGroup.headers.map((header) => (
                  <th key={header.id} className={styles.headerCell}>
                    {flexRender(
                      header.column.columnDef.header,
                      header.getContext()
                    )}
                  </th>
                ))}
              </tr>
            ))}
          </thead>
          <tbody>
            {table.getRowModel().rows.map((row) => (
              <Row key={row.id} row={row} />
            ))}
          </tbody>
        </table>
      </SortableContext>
    </DndContext>
  );
}

export default Table;

Upvotes: 1

Views: 275

Answers (1)

Thijs
Thijs

Reputation: 738

Here's an example with working row selection and drag and drop: https://codesandbox.io/p/sandbox/broken-row-selection-forked-93vdlc?workspaceId=ws_Ugp8jRneUmKth2oi4rosAj

I manually placed the DragHandle in the return of the Row since it seemed to break when rendered by flexRender, not sure why.

<td key={cell.id} className={styles.cell}>
  {index === 1 ? <DragHandle row={row} /> : null}
  {flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>

Upvotes: 0

Related Questions