0

I have a User Table which populates and displays data in a Tanstack Table. Some columns have the sorting feature. Now I am trying to make certain columns editable. Ex: The status column needs to be editable with a drop down of populated status, the roles column needs to be editable to text.

Code Snippet:

import { ColumnDef } from '@tanstack/react-table'
import { Button } from 'flowbite-react'
import Link from 'next/link'
import { I_UserPublic } from 'app/models/user.types'

// This type is used to define the shape of our data.
export type UserDescriptor = {
    id: string;
    firstName: string;
    lastName: string;
    userName: string;
    email: string;
    phone: string;
    title: string;
    organization: string;
    cocom: string;
    base: string;
    role: string[];
    status: string;
}

export const columns: ColumnDef<I_UserPublic>[] = [
    {
        accessorKey: "firstName",
        header: "First Name",
        enableResizing: true,
    },
    {
        accessorKey: "lastName",
        header: "Last Name",
    },
    {
        accessorKey: "userName",
        header: "Username",
    },
    {
        accessorKey: "email",
        header: ({ column }) => {
            return (
                <span className="flex justify-between">
                    Email
                    <Link className="" href="#" onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}>
                        <svg className="w-4 h-4 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
                            <path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M7 4v16M7 4l3 3M7 4 4 7m9-3h6l-6 6h6m-6.5 10 3.5-7 3.5 7M14 18h4"/>
                        </svg>
                    </Link>
                </span>
            )
        },
    },
    {
        accessorKey: "phone",
        header: "Phone",
    },
    {
        accessorKey: "function",
        header: "Function Area",
    },
    {
        accessorKey: "organization",
        header: ({ column }) => {
            return (
                <span className="flex justify-between">
                    Branch
                    <Link className="mx-4" href="#" onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}>
                        <svg className="w-4 h-4 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
                            <path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M7 4v16M7 4l3 3M7 4 4 7m9-3h6l-6 6h6m-6.5 10 3.5-7 3.5 7M14 18h4"/>
                        </svg>
                    </Link>
                </span>
            )
        },
    },
    {
        accessorKey: "cocom",
        header: ({ column }) => {
            return (
                <span className="flex justify-between">
                    COCOM
                    <Link className="mx-4" href="#" onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}>
                        <svg className="w-4 h-4 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
                            <path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M7 4v16M7 4l3 3M7 4 4 7m9-3h6l-6 6h6m-6.5 10 3.5-7 3.5 7M14 18h4"/>
                        </svg>
                    </Link>
                </span>
            )
        },
    },
    {
        accessorKey: "base",
        header: ({ column }) => {
            return (
                <span className="flex justify-between">
                    Base
                    <Link className="" href="#" onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}>
                        <svg className="w-4 h-4 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
                            <path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M7 4v16M7 4l3 3M7 4 4 7m9-3h6l-6 6h6m-6.5 10 3.5-7 3.5 7M14 18h4"/>
                        </svg>
                    </Link>
                </span>
            )
        },
    },
    {
        accessorKey: "role",
        header: ({ column }) => {
            return (
                <span className="flex justify-between">
                    User Role
                    <Link className="" href="#" onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}>
                        <svg className="w-4 h-4 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
                            <path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M7 4v16M7 4l3 3M7 4 4 7m9-3h6l-6 6h6m-6.5 10 3.5-7 3.5 7M14 18h4"/>
                        </svg>
                    </Link>
                </span>
            )
        },
    },
    {
        accessorKey: "status",
        header: ({ column }) => {
            return (
                <span className="flex justify-between">
                    User Status
                    <Link className="" href="#" onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}>
                        <svg className="w-4 h-4 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
                            <path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M7 4v16M7 4l3 3M7 4 4 7m9-3h6l-6 6h6m-6.5 10 3.5-7 3.5 7M14 18h4"/>
                        </svg>
                    </Link>
                </span>
            )
        },
    },
]

The accessorKey are pulled from another file where i have hard coded data i am using for populating.

I have tried using tags from the tanstack table to make it either a dropdown or edit but cant seem to figure it out. Just want to be able to edit the populated data because this will be used as an user form to change status and role based.

2 Answers 2

0

You can specify how the cell is rendered using the cell attribute in your column config like this: cell: (info) => info.getValue(). So if you wanted to render a controlled text input in the "role" column, you could do something like:

    {
      accessorKey: "role",
      cell: (info) => {
        return <input type="text" value={info.getValue()} onChange={handleChange}/>
      },
    },

where handleChange updates the data being passed into the table

Sign up to request clarification or add additional context in comments.

4 Comments

Thank You! I was reading up an article that uses the cell attribute as well @PeterSmith
You’re very welcome. If this answer solves your issue, please mark it as accepted.
@peter i did have an issue. So the field is editable now where i have a text box but the original data is not being populated into the column. I suppose its not getting the value.
Probably because we're rendering an <input type='text'/> in the cell because you asked for this: "the roles column needs to be editable to text." So the input is looking the role property to be a string, but according to your UserDescriptor type def above, it appears the role property is actually an array of strings. So you may need to use a different input element.
0

Tanstack has a rather extensive example for editable tables which shows some interesting techniques.

https://tanstack.com/table/latest/docs/framework/react/examples/editable-data

Use the CodeSandbox link in the example to try it out.

It also illustrates how to apply the changes back into the table data onBlur, uses a function attached to the table's metadata to do this, and it makes all cells editable using a default column:

const defaultColumn: Partial<ColumnDef<Person>> = {
  cell: ({ getValue, row: { index }, column: { id }, table }) => {
    const initialValue = getValue()
    // We need to keep and update the state of the cell normally
    const [value, setValue] = React.useState(initialValue)

    // When the input is blurred, we'll call our table meta's updateData function
    const onBlur = () => {
      table.options.meta?.updateData(index, id, value)
    }

    // If the initialValue is changed external, sync it up with our state
    React.useEffect(() => {
      setValue(initialValue)
    }, [initialValue])

    return (
      <input
        value={value as string}
        onChange={e => setValue(e.target.value)}
        onBlur={onBlur}
      />
    )
  },
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.