MUI DataGrid 单选值

4

所以我试图避免构建自己的选择器,只想将类型设置为singleSelect。所以我已经到了一个点,选择器渲染出来时,双击单元格会显示选项。我遇到的两个问题是,我不确定如何设置哪个选项被选中,当我点击一个选项时,我会收到一个关于“组件正在将一个不受控制的输入变为受控制的”的错误。我看过的所有文档都展示了当你的选项是简单字符串时的情况。

列定义

const columns: GridColDef[] = [
  …
  {
    field: ‘payment’,
    flex: 1,
    editable: true,
    type: ‘singleSelect’,
    getOptionLabel: (value: any) => value.name,
    getOptionValue: (value: any) => value.id,
    valueOptions: (params: GridValueOptionsParams<TMyProps>) => {
      const options = params.row?.attendee?.pricingOptions || [];

      if (options.length === 0) {
        return [
          id: 0,
          name: ‘No pricing options’,
        ];
      }

      return options;
    }, 
  },
  …
];

行数据

const rows = [
  {
     id: 1,
     attendee: {
       id: 1234,
       pricingOptions: [
         {
           id: 2342342342,
           name: ‘Credit Card’,
           selectedOption: true,
         },
         {
           id: 99994,
           name: ‘Cash’,
           selectedOption: false,
         },
       ],
     }
  },
];

所以我不确定如何告诉数据表格如何找到选定的选项。另外,当我点击某个东西时,我该如何控制它?


你所有的行都有payment字段设置为有效值吗(即使它是默认值或空值)从一开始就设置好了吗? - VonC
啊,也许问题在于我没有正确地映射字段。API的工作方式是,在pricingOptions1st中有一个名为selectedOption的属性,如果该属性为true,则表示该选项被选中。 - jrock2004
@VonC 我在想,字段“payment”应该是类似于字段“attendee.pricingOptions”吗? - jrock2004
根据这个结构,如果你设置field: 'attendee.pricingOptions',它会期望attendee.pricingOptions的值是被选中的值。然而,attendee.pricingOptions是一个数组。你可以为DataGrid扁平化你的行数据结构,在每一行添加一个payment字段,该字段将是所选定的定价选项的id。然后将字段设置为payment。当用户进行更改时,您需要处理此编辑并更新原始数据结构(onEditCellChangeCommit)。 - VonC
1个回答

1

疑问

MUI DataGrid仅接受ReactNode作为有效选项,因此字符串作为有效选项可以被接受并渲染。您正在尝试使用对象,但这并不意味着您不能实现您想要的效果。

关于您的第一个问题 -

我不确定如何设置哪个选项被选中

选项是基于列定义的field值来考虑的,如果它是一个有效的ReactNode,您就可以继续使用它。

至于您的第二个问题 -

当我点击一个选项时,出现关于“组件正在将不受控输入变为受控输入”的错误。

MUI的所有组件都会进行引用检查,以确保在受控状态下,输入值保持一致。在您的情况下,一种情况下您手动返回一个数组,而另一种情况下您从行中返回options。这就是为什么MUI说似乎您正在从不受控状态转换为受控状态。

如何实现这一点?

您需要利用通过GridSingleSelectColDef接口提供的所有不同功能,如下所示:

import * as React from "react";
import {
  GridRowsProp,
  DataGrid,
  GridColDef,
  GridRowModel
} from "@mui/x-data-grid";
import { randomId } from "@mui/x-data-grid-generator";

const initialRows: GridRowsProp = [
  {
    id: randomId(),
    attendee: {
      id: randomId(),
      pricingOptions: [
        { id: randomId(), name: "Credit Card", selected: false },
        { id: randomId(), name: "Cash", selected: false },
        { id: randomId(), name: "Net Banking", selected: true },
        { id: randomId(), name: "Free", selected: false }
      ]
    }
  },
  {
    id: randomId(),
    attendee: {
      id: randomId(),
      pricingOptions: [
        { id: randomId(), name: "Credit Card", selected: true },
        { id: randomId(), name: "Net Banking", selected: false },
        { id: randomId(), name: "Debit Card", selected: false },
        { id: randomId(), name: "Free", selected: false }
      ]
    }
  },
  {
    id: randomId(),
    attendee: {
      id: randomId(),
      pricingOptions: [
        { id: randomId(), name: "Credit Card", selected: false },
        { id: randomId(), name: "Cash", selected: true },
        { id: randomId(), name: "Net Banking", selected: false },
        { id: randomId(), name: "Debit Card", selected: false }
      ]
    }
  },
  {
    id: randomId(),
    attendee: {
      id: randomId(),
      pricingOptions: [
        { id: randomId(), name: "Credit Card", selected: false },
        { id: randomId(), name: "Cash", selected: false },
        { id: randomId(), name: "Net Banking", selected: false },
        { id: randomId(), name: "Debit Card", selected: true },
        { id: randomId(), name: "Free", selected: false }
      ]
    }
  },
  {
    id: randomId(),
    attendee: {
      id: randomId(),
      pricingOptions: []
    }
  }
];

export default function SingleSelectAsObject() {
  const [rows, setRows] = React.useState(initialRows);

  const processRowUpdate = (newRow: GridRowModel) => {
    const updatedRow = { ...newRow, isNew: false };
    setRows(rows.map((row) => (row.id === newRow.id ? updatedRow : row)));
    return updatedRow;
  };

  const columns: GridColDef[] = [
    { field: "id", headerName: "ID", width: 320, editable: true },
    {
      field: "attendee",
      headerName: "Payment Options",
      width: 220,
      editable: true,
      type: "singleSelect",
      getOptionLabel: (value: any) => {
        return value?.name;
      },
      getOptionValue: (value: any) => value?.name,
      valueGetter: (option) => {
        const value =
          option?.value?.pricingOptions?.find((opt) => !!opt.selected)?.name ||
          "";
        return value;
      },
      valueOptions: (params) => {
        const options: Array<any> =
          rows.find((row) => row?.id === params.row?.id)?.attendee
            ?.pricingOptions || [];
        if (!options?.length) {
          options.push({
            id: randomId(),
            name: "No Pricing Option",
            selected: true
          });
          return options;
        } else {
          return options;
        }
      },
      valueSetter: (params) => {
        const newRow = {
          ...params.row,
          attendee: {
            ...params.row?.attendee,
            pricingOptions: params.row?.attendee?.pricingOptions?.map((opt) => {
              if (opt?.name === params?.value) {
                return { ...opt, selected: true };
              }
              if (opt?.name !== params?.value && !!opt?.selected) {
                return { ...opt, selected: false };
              }
              return opt;
            })
          }
        };
        return newRow;
      }
    }
  ];

  return (
    <DataGrid
      rows={rows}
      columns={columns}
      editMode="row"
      processRowUpdate={processRowUpdate}
    />
  );
}


这是一个Codesandbox链接
注意 - 我使用了processRowUpdate属性,这并非必需。我只是喜欢使用它。另外,保持行在useState中,像我这样使用状态变量,而不是直接使用变量。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接