自动完成中的嵌套类别 - 选择后重置/清除

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

我正在构建一个 UI,用于使用“嵌套”自动完成组件按类别过滤产品。

我有一个面包屑来显示当前选择的类别,并自动完成以选择当前级别中的类别。

类别由不同深度的树表示(最多可达 20 个),例如:

Women > Accessories > Glasses
Women > Underwear
Men > Shoes > Sandals

在上面的示例中,有 3 个类别级别(但可以不止这个)。

首先,用户可以从选项中进行选择

[Women, Men]
。然后,他可以从所选选项的第二级中选择一个选项。如果用户选择
Women
,他现在可以在
[Accessories, Underwear]
之间进行选择。面包屑将相应更新。

我的问题是,选定的选项在选择后保留,而我在幕后更改选项列表。这会产生以下警告(我想摆脱它):

 MUI: The value provided to Autocomplete is invalid. None of the options match with `"Women"`.You can use the `isOptionEqualToValue` prop to customize the equality test.

此外,“最后”选择的选项保留在文本框中,我希望它为空以供新选择(不同类别级别)。我该怎么做?

这里是一个代码沙箱,显示了我的用例。

type CategoryLevel = {
  [key: string]: CategoryLevel;
};

function getCurrentCategoriesList(
  categoriesTree: CategoryLevel,
  categories: string[]
) {
  let subTree = categoriesTree;
  for (const category of categories) {
    subTree = subTree[category] || {};
  }

  if (!subTree) {
    return [];
  }
  return Object.keys(subTree);
}

export default function App() {
  const [open, setOpen] = useState(false);
  const [options, setOptions] = useState<string[]>([]);
  const [categories, setCategories] = useState<string[]>([]);

  useEffect(() => {
    const newOptions = getCurrentCategoriesList(categoriesTree, categories);
    setOptions(newOptions);
  }, [categories]);

  function handleCategoryChange(_event, newValue: string | null) {
    if (newValue != null) {
      setCategories([...categories, newValue]);
    }
  }

  return (
    <Box className="App">
      <h1>Hello Categories</h1>
      <h2>
        <Button onClick={() => setCategories([])}>Reset</Button>
        {categories.join(" > ")}
      </h2>

      <FormControl>
        <Autocomplete
          disableClearable
          open={open}
          sx={{ width: 300 }}
          onClose={() => {
            setOpen(false);
          }}
          onOpen={() => {
            setOpen(true);
          }}
          noOptionsText="No Categories"
          options={options}
          onChange={handleCategoryChange}
          // onInputChange={handleInputChange}
          renderInput={(params) => (
            <TextField
              {...params}
              label={
                getCurrentCategoriesList(categoriesTree, categories).length > 0
                  ? "Category"
                  : "NA"
              }
              variant="standard"
            />
          )}
        />
      </FormControl>
    </Box>
  );
}


categoriesTree = {
  Men: {
    "T-Shirts": {
      Polos: {},
    },
    Shorts: {},
    Jackets: {},
    Accessories: {
      Glasses: {},
      Belts: {},
      Underwear: {},
      Socks: {},
    },
  },
  Women: {
    "T-Shirts": {
      Polos: {},
    },
    Shorts: {},
    Jackets: {},
    Accessories: {
      Glasses: {},
      Belts: {},
      Underwear: {},
      Socks: {},
    },
  },
};

reactjs typescript material-ui autocomplete
1个回答
0
投票

我的解决方案是使用Free Solo

旨在涵盖搜索输入的主要用例 建议

所以我最终进行了以下更改:

  1. freeSolo
    添加
    Autocomplete
    道具。
  2. 添加
    searchValue
    状态来存储
    value
    inputValue
    道具的当前值。
  3. 更新
    onChange
    本身的
    TextField
    中的值(而不是在
    Autocomplete
    事件中)。

代码沙箱

更新代码:

type CategoryLevel = {
  [key: string]: CategoryLevel;
};

function getCurrentCategoriesList(
  categoriesTree: CategoryLevel,
  categories: string[]
) {
  let subTree = categoriesTree;
  for (const category of categories) {
    subTree = subTree[category] || {};
  }

  if (!subTree) {
    return [];
  }
  return Object.keys(subTree);
}

export default function App() {
  const [open, setOpen] = useState(false);
  const [options, setOptions] = useState<string[]>([]);
  const [categories, setCategories] = useState<string[]>([]);
  const [searchValue, setSearchValue] = useState("");

  useEffect(() => {
    const newOptions = getCurrentCategoriesList(categoriesTree, categories);
    setOptions(newOptions);
  }, [categories]);

  function handleCategoryChange(_event, newValue: string | null) {
    if (newValue != null) {
      setCategories([...categories, newValue]);
      setSearchValue("");
    }
  }

  return (
    <Box className="App">
      <h1>Hello Categories</h1>
      <h2>
        <Button onClick={() => setCategories([])}>Reset</Button>
        {categories.join(" > ")}
      </h2>

      <FormControl>
        <Autocomplete
          freeSolo
          disableClearable
          value={searchValue}
          inputValue={searchValue}
          disabled={options.length === 0}
          open={open}
          sx={{ width: 300 }}
          onClose={() => {
            setOpen(false);
          }}
          onOpen={() => {
            setOpen(true);
          }}
          noOptionsText="No Categories"
          options={options}
          onChange={handleCategoryChange}
          renderInput={(params) => (
            <TextField
              {...params}
              label={
                getCurrentCategoriesList(categoriesTree, categories).length > 0
                  ? "Category"
                  : "NA"
              }
              variant="standard"
              onChange={(event) => {
                // don't fire API if the user delete or not entered anything
                if (event.target.value !== null) {
                  setSearchValue(event.target.value);
                }
              }}
            />
          )}
        />
      </FormControl>
    </Box>
  );
}
© www.soinside.com 2019 - 2024. All rights reserved.