使用 React Material-UI 自动完成始终显示默认选项

Posted

技术标签:

【中文标题】使用 React Material-UI 自动完成始终显示默认选项【英文标题】:Always Display Default Option with React Material-UI Autocomplete 【发布时间】:2021-11-17 08:36:57 【问题描述】:

我在 React 中使用 Material-UI Autocomplete 进行地址搜索/验证表单,并且我希望始终有一个默认选项,无论结果如何。

在 Angular 中,我使用 [displayWith] 和一个函数来告诉它始终显示具有特定 ID 的数组中的项目,但我不确定如何在 React 中执行此操作。我一直试图找出filterOptions,但我不希望它根据与输入相关的任何内容进行过滤,我只是希望它始终是一个选项。

在这个简化的示例中,如果我希望它始终显示带有年份的电影:1111,我该怎么做?

import React,  useState, ChangeEvent  from 'react';
import 
  TextField,
  InputAdornment
 from "@material-ui/core";
import Autocomplete from '@material-ui/lab/Autocomplete';
import  Search  from "@material-ui/icons";
import axios from "axios";

const AddressSearch = (props) => 

  const [addressesList, setAddressesList] = useState([]);
  const [inputAddress, setInputAddress] = useState<string>("");

  const handleAddressChange = (event: ChangeEvent< value: unknown >) => 
    setInputAddress(event.target.value as string);
  ;

  const topFilms = [
     title: 'I HATE MOVIES', year: 1111 ,
     title: 'The Shawshank Redemption', year: 1994 ,
     title: 'The Godfather',
     title: 'The Godfather: Part II', year: 1974 
  ]

  return (
    <div>
      <Autocomplete
        id="address-autocomplete"
        freeSolo
        options=topFilms
        getOptionLabel=(option) => option.title
        popupIcon=<Search />
        renderInput=(params) => <TextField 
          id="address-input"                          
          ...params 
          onChange=handleAddressChange
          placeholder="Quickly find your address" 
          InputProps= ...params.InputProps,
          startAdornment: (
            <InputAdornment position="start"><Search /></InputAdornment>
          )
        /> 
      />
    </div>
  );


export default AddressSearch;

注意:我正在使用的网站使用的是 Material-UI v 4.12

【问题讨论】:

【参考方案1】:

您可以创建filterOptions 的包装器,而无需触及原始filterOptions 中的任何内容。只需像往常一样过滤,获取结果,看看是否有默认选项,如果没有,请重新添加:

import TextField from "@mui/material/TextField";
import Autocomplete,  createFilterOptions  from "@mui/material/Autocomplete";

const _filterOptions = createFilterOptions();
const filterOptions = (options, state) => 
  const results = _filterOptions(options, state);

  if (!results.includes(myDefaultOption)) 
    results.unshift(myDefaultOption);
  

  return results;
;

export default function ComboBox() 
  return (
    <Autocomplete
      filterOptions=filterOptions
      options=options
      sx= width: 300 
      renderInput=(params) => <TextField ...params label="Movie" />
    />
  );


const myDefaultOption =  label: "My default option", year: 1994 ;

const options = [
  myDefaultOption,
  ...
]

现场演示

【讨论】:

【参考方案2】:

编辑:根据您的评论,您想从源中获取固定值,因此我进行了一些更改。

编辑:添加您的年份:1111 示例。

CodeSandbox

...

您可以将 filterOptions Docs 添加到 Autocomplete 元素,然后将 固定值 添加到结果中。

过滤选项和来源: Link to documentation

const filterOptions = createFilterOptions(
  ignoreCase: true,
  ignoreAccents: true
)

const topFilms = [
   title: 'Elysium', year: 2013 ,
   title: 'I HATE MOVIES', year: 1111 ,
   title: 'The Shawshank Redemption', year: 1994 ,
   title: 'The Godfather' ,
   title: 'The Godfather: Part II', year: 1974 
]

addressesList 状态存储您要修复的值的标题,我从您的代码中获取了这个钩子

const [addressesList, setAddressesList] = useState([1111])

从源中取出固定值,因此它们不会重复,此过滤器只会触发一次,或者如果源或“addressesList”发生变化。

const fixedValues = useMemo(() => topFilms.filter(e => addressesList.includes(e.year)), [topFilms, addressesList])
const dynamicValues = useMemo(() => topFilms.filter(e => !addressesList.includes(e.year)), [topFilms, addressesList])

自动完成组件的变化。

<Autocomplete
   filterOptions=(options, _ref) => [...fixedValues, ...filterOptions(options, _ref)]
   ...Other attributes
/>

最终代码:

import React,  useState, ChangeEvent, useMemo  from 'react'
import  TextField, InputAdornment  from "@material-ui/core"
import Autocomplete,  createFilterOptions  from '@material-ui/lab/Autocomplete'
import  Search  from "@material-ui/icons"

const filterOptions = createFilterOptions(
  ignoreCase: true,
  ignoreAccents: true
)

const topFilms = [
   title: 'Elysium', year: 2013 ,
   title: 'I HATE MOVIES', year: 1111 ,
   title: 'The Shawshank Redemption', year: 1994 ,
   title: 'The Godfather' ,
   title: 'The Godfather: Part II', year: 1974 
]

const AddressSearch = (props) => 

  const [addressesList, setAddressesList] = useState([1111])
  const [inputAddress, setInputAddress] = useState("")

  const handleAddressChange = (event) => 
    setInputAddress(event.target.value)
  

  const fixedValues = useMemo(() => topFilms.filter(e => addressesList.includes(e.year)), [topFilms, addressesList])
  const dynamicValues = useMemo(() => topFilms.filter(e => !addressesList.includes(e.year)), [topFilms, addressesList])

  return (
    <div>
      <Autocomplete
        id="address-autocomplete"
        freeSolo
        options=dynamicValues
        getOptionLabel=(option) => option.title
        popupIcon=<Search />
        filterOptions=(options, _ref) => [...fixedValues, ...filterOptions(options, _ref)]
        renderInput=(params) => <TextField
          id="address-input"
          ...params
          onChange=handleAddressChange
          placeholder="Quickly find your address"
          InputProps=
            ...params.InputProps,
            startAdornment: (
              <InputAdornment position="start"><Search /></InputAdornment>
            )
          
        />
      />
    </div>
  )


export default AddressSearch

【讨论】:

以上是关于使用 React Material-UI 自动完成始终显示默认选项的主要内容,如果未能解决你的问题,请参考以下文章

如何在 onChange 后清除 Material-ui 中的自动完成输入?

使用 React Material-UI 自动对焦 TextField

自动完成中的 React Material UI 打开模式失去焦点

React + Material-UI |如何创建水平滚动卡片?

Material-ui 自动完成过滤列表

MUI 自动完成功能不适用于 react-hook-form