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

标签 reactjs arrays typescript material-ui datagrid

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

所需的功能如下:

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

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

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

Code Sandbox

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>
  )
}

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

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

在这里你可以看到排序没有效果: data-grid-sort-not-working

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

最佳答案

您需要将自定义 sortComparatorfilterOperators 属性设置为相关列定义,如下所示:

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>
  )
}

您可以看看this sandbox有关此解决方案的实时工作示例。

关于reactjs - 如何使用 MUI 的数据网格对多值数组列启用过滤和排序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73942398/

相关文章:

javascript - 如何访问 xml 提要上的属性

typescript - 过滤掉联合类型中的一种可能性

typescript Jest 全局变量示例

c# - 从字符串数组中排序日期

javascript - 如何在 Javascript 中从数组创建变量数组

java - 如何让用户选择任何电影

javascript - TypeScript:匿名类工厂

reactjs - VS17 Resharper 提示 React.Component

javascript - 如何自定义react-calendar以一次只显示一周?

javascript - 如何在草稿 js 编辑器中渲染提供的 HTML?