Как установить максимальное количество элементов, которые можно выбрать в response-select?

Я использую компонент CreatableSelect из response-select. Теперь пользователи могут выбирать столько элементов, сколько хотят, но я хочу, чтобы пользователи выбирали не более 5 элементов. Как ограничить максимальное количество вариантов, которые можно выбрать?

<CreatableSelect
  classes={classes}
  styles={selectStyles}
  textFieldProps={{
    label: "Tags"
  }}
  options={suggestions}
  components={components}
  value={this.state.multi}
  onChange={this.handleChange("multi")}
  placeholder=""
  isMulti
/>

person Bositkhon Sultonov    schedule 12.03.2019    source источник
comment
Добавив эту логику в onChange обработчик. Просто оставьте выделенными первые пять.   -  person remix23    schedule 12.03.2019
comment
Что ты имеешь в виду? Можете уточнить или показать код?   -  person Bositkhon Sultonov    schedule 12.03.2019
comment
Допустим, ваш обработчик получает новый выбор каждый раз, когда он изменяется, я предполагаю, что аргументом обработчика будет выбор в виде массива. Затем просто нарежьте этот массив при вызове setState(() => ({ multi: selectionArray.slice(4) })).   -  person remix23    schedule 12.03.2019
comment
В качестве альтернативы вы можете разрезать конец массива, чтобы получить последний выбор, это зависит от того, как результаты передаются обработчику.   -  person remix23    schedule 12.03.2019


Ответы (7)


Я рекомендую вам использовать комбинацию пользовательских компонентов Menu и isValidNewOption, например, следующий код:

// For this example the limite will be 5
    const Menu = props => {
      const optionSelectedLength = props.getValue().length || 0;
      return (
        <components.Menu {...props}>
          {optionSelectedLength < 5 ? (
            props.children
          ) : (
            <div>Max limit achieved</div>
          )}
        </components.Menu>
      );
    };

    function App() {
      const isValidNewOption = (inputValue, selectValue) =>
        inputValue.length > 0 && selectValue.length < 5;
      return (
        <div className="App">
          <Creatable
            components={{ Menu }}
            isMulti
            isValidNewOption={isValidNewOption}
            options={options}
          />
        </div>
      );
    }

Вот живой пример.

Идея состоит в том, чтобы запретить пользователю доступ к параметрам после предела X (5 в примере), а также предотвратить событие клавиатуры enter при создании через isValidNewOption prop.

person Laura    schedule 12.03.2019
comment
Большое Вам спасибо. Это помогло мне решить мою проблему. - person Bositkhon Sultonov; 12.03.2019
comment
Это не сработает, если вы вручную введете другую опцию и нажмете клавишу ввода, или если вы введете и нажмете вкладку - это позволит ввести больше записей, чем заданный предел. - person chapmanio; 28.02.2020
comment
Я не вижу другого с и без isValidNewOption tbh - person nickornotto; 21.06.2020
comment
@nickornotto, если вы не используете isValidNewOption, вы все равно увидите Max limit achieved, но если вы начнете вводить текст, который не соответствует ни одному параметру, вы сможете создать новый параметр и превысить лимит - person Laura; 21.06.2020
comment
Хорошо, спасибо, пробовал только с Select, имеет смысл с Creatable - person nickornotto; 21.06.2020

Основную документацию о том, как решить эту проблему, можно найти здесь:

https://github.com/JedWatson/react-select/issues/1341

const MultiCreatable = ({ options, handleChange, handleCreate, value, maxOptions }) => {
  return (
    <CreatableSelect
      isMulti
      placeholder={placeholder}
      onChange={handleChange}
      options={value.length === maxOptions ? [] : options}
      noOptionsMessage={() => {
        return value.length === maxOptions ? 'You have reached the max options value' : 'No options available' ;
      }}
      onCreateOption={handleCreate}
      value={value}
    />
  )
}
person Marc Raaz    schedule 13.08.2020
comment
Пожалуйста, объясните свой код, что он делает и как он это делает, чтобы ответить на вопрос. - person Our Man in Bananas; 13.08.2020

В моем случае я использовал обычный компонент Select из response-select.

<Select 
     options={industries}
     value={industry}
     getOptionLabel={ x => x.id}
     getOptionValue={ x => x.industry}
     onChange={(e) => this.handleSelectChange(e, "industry")}
     isMulti
/>

и handleSelectChange-

handleSelectChange = (e, name) => {
    console.log(e)
    if(e.length < 6){
        return this.setState({
            [name]: e
        })
    }
}

и состояние -

this.state = { industry: [] }
person Tron    schedule 04.06.2020

Я делюсь своим полностью работающим компонентом, думаю, это может помочь ››

import React, { useState } from 'react';
import Select from 'react-select';
import makeAnimated from 'react-select/animated';
const animatedComponents = makeAnimated();

const ReactSelect = ({ data }) => {
    const maxOptions = 5;
    const [selectedOption, setSelectedOption] = useState([]);
    const handleTypeSelect = e => {
        setSelectedOption(e);
    };

    return (
        <Select
            onChange={handleTypeSelect}
            getOptionLabel={x => x.name}
            getOptionValue={x => x.slug}
            components={animatedComponents}
            isMulti
            options={selectedOption.length === maxOptions ? [] : data}
            noOptionsMessage={() => {
                return selectedOption.length === maxOptions
                    ? 'You have reached the max options value'
                    : 'No options available';
            }}
            label='tags'
        />
    );
};

export default ReactSelect;
person Devesh    schedule 29.01.2021

очень простой способ сделать это:

<Select
        value={tags}
        onChange={(v) => v.length < 4 ? setTags(v): null}
        isMulti
        name='tags'
        options={options}
        className='basic-multi-select'
        classNamePrefix='select'
      />

просто добавьте простую тройную проверку того, сколько элементов вы хотите

person Methkal Khalawi    schedule 13.02.2021

Я нашел способ более простой и понятный, без лишних манипуляций. Этот способ основан на отключении компонента ввода «response-select». Присмотритесь к параметру inputProps.

Это может выглядеть так:

import Select from 'react-select';
import useField from 'client/components/hooks/useField';

const MultiSelect = ({
  async,
  creatable,
  maxItems,
  ...restProps,
}) => {
  const selectProps = {
    ...restProps,
    // "inputProps: {disabled: boolean}" - our goal
    ...(typeof maxItems === 'number' && maxItems === restProps.value?.length ? {inputProps: {disabled: true}} : {}) 
  };
  const creatableTag = async ? Select.CreatableAsync : Select.Creatable;
  const SelectTag = creatable ? creatableTag : selectTag;

  return (
    <div>
      <SelectTag {...selectProps} />
    </div>
  );
};

const SomeComponentWithMultiSelect = () => {
  const field = useField('data.name'); // field contains: {value: string[], ...}
  const items = [
    {
      label: 'firstValue',
      value: 1,
    },
    {
      label: 'secondValue',
      value: 2,
    },
  ];

  return (
    <MultiSelect
      items={items}
      {...field}
      creatable
      maxItems={1} // {1} as our limit
    />
  )
};

export default SomeComponentWithMultiSelect;

Таким образом, вам не нужно управлять лишними компонентами.

person av-k    schedule 26.03.2021

person    schedule
comment
Добавление проверки на options и установка данных только в том случае, если ниже лимита является полное решение. - person chapmanio; 28.02.2020