material-react-table icon indicating copy to clipboard operation
material-react-table copied to clipboard

updated value is not displayed with custom Edit component

Open githorse opened this issue 2 years ago • 6 comments

material-react-table version

v1.14.0

react & react-dom versions

v18.2.0

Describe the bug and the steps to reproduce it

Following the pattern from this discussion on custom edit components, I've created a simple example with a custom Select widget here. Here's the relevant part:

{
  accessorKey: "state",
  header: "State",
  Edit: ({ row, cell }) => (
    <Select
      value={cell.getValue<string>()}
      onChange={(e) => (row._valuesCache["state"] = e.target.value)}
    >
    <MenuItem key="Alabama" value="Alabama">
      Alabama
    </MenuItem>
    <MenuItem key="Zanzibar" value="Zanzibar">
         Zanzibar
       </MenuItem>
     </Select>
  ),
}

Selecting a value does actually set the new value, which I can see after hitting the Save button -- but it does not update the temporary value displayed while editing, so there's no visual indication that a new item was selected. (This is complicated to explain but trivial to see -- just try the demo.)

I thought that this change might fix it:

<Select
  value={row._valuesCache["state"]}
  onChange={(e) => (row._valuesCache["state"] = e.target.value)}
>

But surprisingly that had no effect.

In general the row._valuesCache thing seems problematic ... seems like we need a more principled way of accessing and setting the row state in a custom editor. For reference, here's how MUI does it -- though I don't particularly like their solution. Seems to me the cleanest and most elegant solution is for Edit params to just give me what I need:

{
  accessorKey: "state",
  header: "State",
  Edit: ({ value, setValue }) => (  // <-- notional new props here
    <Select
      value={value}
      onChange={e => setValue(e.target.value)}
    >
    <MenuItem key="Alabama" value="Alabama">
      Alabama
    </MenuItem>
    <MenuItem key="Zanzibar" value="Zanzibar">
         Zanzibar
       </MenuItem>
     </Select>
  )
}

(If setValue just calls row._valuesCache[accessorKey] = value under the hood, great, but as the MRT user I'd rather not know about it.)

Minimal, Reproducible Example - (Optional, but Recommended)

See CodeSandbox demo.

Screenshots or Videos (Optional)

No response

Do you intend to try to help solve this bug with your own PR?

No, because I do not know how

Terms

  • [X] I understand that if my bug cannot be reliably reproduced in a debuggable environment, it will probably not be fixed and this issue may even be closed.

githorse avatar Jun 28 '23 19:06 githorse

@githorse did you able to solve this issue? I'm also facing this issue

mbmohib avatar Aug 07 '23 04:08 mbmohib

@mbmohib Unfortunately not. At the moment I'm just using the built-in select functionality, like this:

{
  ...
  muiTableBodyCellEditTextFieldProps: {
    select: true,
    options: myOptions.map(({value, label}) => (
      <MenuItem key={value} value={value}>{label}</MenuItem>
    )
} 

But it's not what I want -- my actual custom Select widget has other functionality (styling) that I'm missing here.

githorse avatar Aug 08 '23 15:08 githorse

After hours of digging: table.options.data

Drecula avatar Aug 09 '23 02:08 Drecula

@Drecula could you elaborate? What do I do with table.options.data?

githorse avatar Aug 09 '23 12:08 githorse

@githorse If you check the TextField component, whenever you change the table gets re-rendered. But with the custom component when we update the cache value, it does not re-render. So if we make the parent component force to rerender, you will see this value will be populated.

mbmohib avatar Sep 12 '23 07:09 mbmohib

for those who are suffering from the same issue us the function row.toggleSelected this will update the component after value is changed>

  {
    type: "autoComplete",
    autoCompleteOptions: roles.data,
    header: "الدور",
    accessorKey: "role",
    enableHiding: false,
    Edit: ({ row }) => {
      return (
        <Autocomplete
          disablePortal
          id={"autoComplete"}
          key={"autoComplete"}
          value={row._valuesCache["role"] || null}
          onChange={(_, value) => {
            row._valuesCache["role"] = value;
            row.toggleSelected(row._valuesCache["role"]);
          }}
          isOptionEqualToValue={(option, value) => option._id === value._id}
          getOptionLabel={(option) => option.title}
          fullWidth
          options={roles.data || []}
          renderInput={(params) => (
            <TextField
              key={"autoCompleteText"}
              {...params}
              label={"الدور"}
            />
          )}
        />
      );
    },
  },

mohfrea avatar Sep 12 '23 12:09 mohfrea