如何限制 Material UI 实验室自动完成组件中可以选择的最大选项数

Posted

技术标签:

【中文标题】如何限制 Material UI 实验室自动完成组件中可以选择的最大选项数【英文标题】:How Can i limit the maximum number of options that can be selected in a Material UI lab Autocomplete component 【发布时间】:2021-03-14 00:19:46 【问题描述】:

(例如)我希望限制用户在我的自动完成组件中仅选择 3 个选项,并在 TAG Array 的长度达到 3 时禁用这些选项。 问题是 api 中没有 limitMaxNumberOfTags 选项,我无法获得任何方法来访问 Selected tags 数组除了 limitTags,它只限制可见标签 . 类似的东西可能会有所帮助 getOptionDisabled=(options, tags) => (tags.length > 3 ? true : false) . 到目前为止,这是我的自动完成实现

<Autocomplete
  multiple
  id="tags-outlined"
  options=students
  getOptionLabel=(option) => option.personalInfo.firstName + ' ' + option.personalInfo.lastName
  defaultValue=[...added]
  onChange=(e, newVal) => setAdded([...newVal])
  renderOption=(option, state) => 
    return (
      <Chip
        icon=
          <FaceIcon /> /*<Avatar color="primary" variant='outlined' size="small" className=classes.small></Avatar>*/
        
        label=option.personalInfo.firstName + ' ' + option.personalInfo.lastName
        color="default"
        variant="outlined"
        ...state
      />
    );
  
  renderTags=(options, getTagProps) =>
    options.map((option) => (
      <Chip
        icon=
          <FaceIcon /> /*<Avatar color="primary" variant='outlined' size="small" className=classes.small></Avatar>*/
        
        label=option.personalInfo.firstName + ' ' + option.personalInfo.lastName
        color="primary"
        variant="outlined"
        ...getTagProps()
      />
    ))
  
  filterSelectedOptions
  filterOptions=(options, state) =>
    options.filter((option) => 
      for (let i = 0; i < added.length; i++) 
        if (added[i]._id === option._id) 
          return false;
        
      
      return true;
    )
  
  // --->         getOptionDisabled=(options) => (tags.length > 3 ? true : false)
  renderInput=(params) => (
    <TextField ...params variant="outlined" color="primary" label="Select Students" placeholder="Participant" />
  )
/>

【问题讨论】:

【参考方案1】:

最近遇到了类似的问题。这就是我最终要做的。基本上你必须直接在芯片本身上设置禁用标志,所以它会禁用文本输入,而不是芯片。所以你仍然可以删除每个芯片。

export const AutoCompleteWithLimit: React.FC<Props> = (
  disabled = false,
  limit = 2,
) => 
  const [disableInput, setDisableInput] = useState<boolean>(
    value.length >= limit
  );

  return (
    <Autocomplete
      // Set disabled based on input
      disabled=disabled || disableInput
      multiple
      renderTags=(tagValue, getTagProps) =>
        tagValue.map((option, index) => (
          <Chip
            key=index
            label=option.name
            ...getTagProps( index )
            // Set disable explicitly after getTagProps
            disabled=disabled
          />
        ))
      
      onChange=(_event: any, newValue: any[]) => 
        // do something else
        // set the disable input
        setDisableInput(newValue.length >= limit);
      
    />
  );
;

【讨论】:

【参考方案2】:

Autocomplete 添加了getOptionDisabled 属性,可用于在选择最大选项后禁用所有未选择的选项。

const a = (limit = 3)=> 
    const [limitReached, setLimitReached] = useState(false);
    const [values, setValues] = useState([]);
    const onSelect = useCallback((newValues) => 
        setValues(newValues);
        setLimitReached(newValues.length >= limit);
    , [limit]);


  const checkDisable = useCallback(option => limitReached && !values.includes(option), [limitReached, values]);

  return <Autocomplete
                getOptionDisabled=checkDisable
                multiple
                onChange=onSelect
                options=options
                value=values
            />


【讨论】:

【参考方案3】:

在翻阅文档以解决一些不相关的问题后,我找到了一种自行处理的解决方案。 解决方案包括

    设置value = [...myStateVariable] 使用 onChange((event, newValue, reason)=&gt;....) 回调中的原因参数
            <Autocomplete
                multiple
                id="tags-outlined"
                options=students
                getOptionLabel=(option) => option.personalInfo.firstName+' '+option.personalInfo.lastName
                defaultValue=[...added]
                value=[...added]
                onChange=(e, newVal, reason)=>

                    if(reason==="select-option")
                        addChips(newVal)
                     else if(reason==="remove-option")
                        handleDelete(newVal)
                    
                

HandleDelete 和 addChips 方法如下。

    const [added, setAdded] = useState([...added2])

    const handleDelete = (students)=>
        setAdded([...students])
    

    const addChips = (students)=>
        if(added.length>= maxParticipation)
            alert('Cannot add more participants')
        else
            setAdded([...students])
        
    

'newValue' 首先被 'onChange' 回调拦截,并在其中评估它的长度,如果长度大于限制值,则取消值更新。 (注意,导致进程中止的 onChange 只是 "reason" = 'select-option' 的那个)。 P.S-(忘记提及禁用选项查询)选项上的“禁用”属性也可以在渲染选项中进行操作,以在“newVal”达到给定长度后禁用所有选项。 [@justindra 详细给出的解决方案(禁用选项)]

【讨论】:

【参考方案4】:

在渲染芯片之前,我使用slice 限制了renderTags 的最大限制

<Autocomplete
  renderTags=(options, getTagProps) =>
    options.slice(0, 5).map((option) => (
      <Chip
        icon=
          <FaceIcon /> /*<Avatar color="primary" variant='outlined' size="small" className=classes.small></Avatar>*/
        
        label=option.personalInfo.firstName + ' ' + option.personalInfo.lastName
        color="primary"
        variant="outlined"
        ...getTagProps()
      />
    ))
  
/>

【讨论】:

【参考方案5】:
 <Autocomplete
                  multiple
                  id="role"
                  options=rootStore.roleStore.listRole
                  disableCloseOnSelect
                  value=rootStore.userStore.user.role
                  onChange=(event, newValue) => 
                    setErrors(
                      ...errors,
                      role: Utils.validate.single(
                        newValue,
                        Utils.constraintsUser.role
                      ),
                    )
                    if (newValue.length > 2) 
                      alert("Please select max 2 labs")
                     else 
                      rootStore.userStore.updateUser(
                        ...rootStore.userStore.user,
                        role: newValue,
                      )
                    
                  
                  getOptionLabel=(option) => option.description || ""
                  renderOption=(option,  selected ) => (
                    <React.Fragment>
                      <Checkbox style= marginRight: 8  checked=selected />
                      option.description
                    </React.Fragment>
                  )
                  renderInput=(params) => (
                    <TextField
                      ...params
                      variant="outlined"
                      label="Labs"
                      placeholder="Labs"
                    />
                  )
                />

完美的解决方案..

【讨论】:

对您更改/添加的代码或相关文档的链接的一些解释通常对作者有所帮助。【参考方案6】:

我的解决方案,我认为这是最恰当的方式:

<Autocomplete
  value=selectedTags
  onChange=(ev, value: Tag[]) => 
    if (value.length <= 3) 
      setSelectedTags(value);
     else 
      return;
    
  
/>;

【讨论】:

以上是关于如何限制 Material UI 实验室自动完成组件中可以选择的最大选项数的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Material-UI 自动完成控件中自定义填充?

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

React Formik Material UI Autocomplete:如何从 localStorage 填充自动完成内部的值?

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

样式/更改 Material UI React 中的自动完成关闭图标

Material-ui 自动完成过滤列表