如何使用MUI的数据网格对多值数组列启用过滤和排序?

问题描述 投票:0回答:2

我正在使用免费版本的 MUI 数据网格组件,但无法对在数组中呈现多个值的列进行过滤和排序以正确工作。在此示例中,我的多值数组列是“标签”,它显示数据网格中单词的一些类别。

所需的功能如下:

过滤:我希望用户能够从下拉列表中选择一个标签,并使表格仅显示包含该标签的行。让用户选择多个标签并匹配所有标签也是可以接受的,但这不是必需的。预期的过滤器菜单类似于:“列:标签,运算符:包含,值:[从所有可能标签的列表中选择一个或多个标签]”。

排序:这更容易解释,但至少,它应该对包含标签的所有行在不包含标签的行之前/之后进行排序。

下面是我到目前为止所拥有的,但我相信它不起作用,因为“singleSelect”列类型期望与单个字符串值而不是字符串数组进行比较。然而,浏览 MUI 文档,我无法找到相应的列/过滤器选项,该选项可以将下拉列表中的预定义值与相应字符串数组列中的任何一个值进行匹配。

代码沙箱

import { DataGrid, GridColDef, GridToolbar } from "@mui/x-data-grid"
import { Box, Chip, Stack } from "@mui/material"

export default function App() {
  const rows = [
    { id: 1, german: "der Kuchen", english: "cake", tags: ["food", "baked goods", "kitchen"] },
    { id: 2, german: "rot", english: "red", tags: ["colors"] },
    { id: 3, german: "das Auto", english: "car", tags: ["vehicles", "garage"] },
    { id: 4, german: "fliegend", english: "flying", tags: [] },
    { id: 5, german: "grün", english: "green", tags: ["colors", "nature"] },
    { id: 6, german: "der Hubschrauber", english: "helicopter", tags: ["vehicles"] },
    { id: 7, german: "die Gabel", english: "fork", tags: ["kitchen"] },
    { id: 8, german: "das Hemd", english: "shirt", tags: ["clothes", "closet"] },
    { id: 9, german: "tatsächlich", english: "actual", tags: [] },
    { id: 10, german: "der Bus", english: "bus", tags: ["school", "vehicles"] }
  ]

  const columns: GridColDef[] = [
    { field: "id", headerName: "ID", width: 30, filterable: false },
    { field: "german", headerName: "German", width: 150 },
    { field: "english", headerName: "English", width: 100 },
    {
      field: "tags",
      headerName: "Tags",
      width: 300,
      type: "singleSelect",
      valueOptions: [...new Set(rows.map((o) => o.tags).flat())],
      renderCell: (params) => (
        <Stack direction="row" spacing={0.25}>
          {params.row.tags.map((tag: string) => (
            <Chip label={tag} />
          ))}
        </Stack>
      )
    }
  ]

  return (
    <Box sx={{ height: 500, width: "100%" }}>
      <DataGrid
        rows={rows}
        columns={columns}
        density={"compact"}
        disableSelectionOnClick
        components={{
          Toolbar: GridToolbar
        }}
      />
    </Box>
  )
}

这是尝试过滤数据网格之前的样子:

这是一个过滤未按预期工作的示例(预期行为是当用户选择“车辆”时,表格仅显示第 3、6 和 10 行):

在这里可以看到排序没有效果:

我在其中寻找解决方案的 MUI 文档:

reactjs arrays typescript material-ui datagrid
2个回答
4
投票

您需要为相关列定义设置自定义

sortComparator
filterOperators
属性,如下所示:

import {
  DataGrid,
  getGridSingleSelectOperators,
  GridCellParams,
  GridColDef,
  GridComparatorFn,
  GridFilterItem,
  GridToolbar
} from "@mui/x-data-grid"
import { Box, Chip, Stack } from "@mui/material"

const tagsSortComparator: GridComparatorFn<any> = (tags1: any, tags2: any) => {
  return tags1.length - tags2.length
}

const tagsFilterOperators = getGridSingleSelectOperators()
  .filter((operator) => operator.value === "isAnyOf")
  .map((operator) => {
    const newOperator = { ...operator }
    const newGetApplyFilterFn = (filterItem: GridFilterItem, column: GridColDef) => {
      return (params: GridCellParams): boolean => {
        let isOk = true
        filterItem?.value?.forEach((fv: any) => {
          isOk = isOk && params.value.includes(fv)
        })
        return isOk
      }
    }
    newOperator.getApplyFilterFn = newGetApplyFilterFn
    return newOperator
  })

export default function App() {
  const rows = [
    { id: 1, german: "der Kuchen", english: "cake", tags: ["food", "baked goods", "kitchen"] },
    { id: 2, german: "rot", english: "red", tags: ["colors"] },
    { id: 3, german: "das Auto", english: "car", tags: ["vehicles", "garage"] },
    { id: 4, german: "fliegend", english: "flying", tags: [] },
    { id: 5, german: "grün", english: "green", tags: ["colors", "nature"] },
    { id: 6, german: "der Hubschrauber", english: "helicopter", tags: ["vehicles"] },
    { id: 7, german: "die Gabel", english: "fork", tags: ["kitchen"] },
    { id: 8, german: "das Hemd", english: "shirt", tags: ["clothes", "closet"] },
    { id: 9, german: "tatsächlich", english: "actual", tags: [] },
    { id: 10, german: "der Bus", english: "bus", tags: ["school", "vehicles"] }
  ]

  const columns: GridColDef[] = [
    { field: "id", headerName: "ID", width: 30, filterable: false },
    { field: "german", headerName: "German", width: 150 },
    { field: "english", headerName: "English", width: 100 },
    {
      field: "tags",
      headerName: "Tags",
      width: 300,
      type: "singleSelect",
      valueOptions: [...new Set(rows.map((o) => o.tags).flat())],
      renderCell: (params) => (
        <Stack direction="row" spacing={0.25}>
          {params.row.tags.map((tag: string) => (
            <Chip label={tag} />
          ))}
        </Stack>
      ),
      sortComparator: tagsSortComparator,
      filterOperators: tagsFilterOperators
    }
  ]

  return (
    <Box sx={{ height: 500, width: "100%" }}>
      <DataGrid
        rows={rows}
        columns={columns}
        density={"compact"}
        disableSelectionOnClick
        components={{
          Toolbar: GridToolbar
        }}
      />
    </Box>
  )
}

您可以查看此沙箱,了解此解决方案的实时工作示例。


0
投票

偏离接受的答案 - 如果您需要显示标签,但您的 valueOptions 是 {value, label} 类型的对象,您将需要在列定义中设置 valueGetter 以及上面的 filterOperators 。比如:

valueGetter: (params) => params?.row?.pathToYourValue

已接受的解决方案省去了很多麻烦,我只是缺少适合我的用例的 valueGetter :)

© www.soinside.com 2019 - 2024. All rights reserved.