使用react-select,可以同时选择多个匹配搜索的项目

时间:2018-10-10 17:46:44

标签: javascript reactjs react-select

我正在使用react-select显示可搜索的项目下拉列表,用户可以从中选择多个项目。我的列表很长,用户经常希望选择多个与同一过滤器字符串匹配的项目,这是一个繁琐的过程,因为每次选择一个项目时,下拉菜单都会消失,您需要重新输入搜索。

例如,以下沙箱中有一个react-select,其中列出了很多苹果和奶酪。为了选择所有苹果,必须不断输入“ Apple”并一次选择一个苹果。

https://codesandbox.io/s/2l99lry5p

出于桌面用户界面的背景,我自然希望能够键入搜索查询,然后按Ctrl-A选择所有匹配的搜索结果并将其添加到我的列表中,或将Ctrl-Click添加到樱桃中从匹配集中选择多个项目。但据我所知,react-select中不支持任何此类热键。

react-select API是否可以通过任何方式实现“全选”热键(甚至页面上显式的“全选”按钮也可以)。我看不到任何程序方式来访问与过滤器匹配的对象集。这是我需要分叉react-select来实现的事情,还是可以通过现有的API通过某种方式实现?

4 个答案:

答案 0 :(得分:1)

反应选择具有内置的道具,可用于防止菜单在选择时关闭并保留搜索字符串。

首先通过将closeMenuOnSelect设置为false来防止菜单在选择时关闭。

然后,如果操作等于onInputChange,则state将搜索字符串存储在'input-change'中。

inputValue设置为this.state.value会将搜索字符串保留在输入字段中。

class Foo extends Component {
    constructor(props) {
        super(props);
        this.state = {
            value: ''
        };
    }
    handleInputChange = (value, e) => {
        if (e.action === 'input-change') {
            this.setState({value});
        }
    }
    render() {
        return (
            <Select
                isMulti
                name="colors"
                options={options.map(x => MakeOption(x))}
                className="basic-multi-select"
                classNamePrefix="select"
                /* added these props */
                closeMenuOnSelect={false}
                onInputChange={this.handleInputChange}
                inputValue={this.state.value}
            />
        )
    }
}

更新的沙箱: https://codesandbox.io/s/yvmzx6pn6z

答案 1 :(得分:1)

实现“全选”选项的一种非常简单的方法是使用自定义组件覆盖React-Select组件。为此,您首先需要将其导入为

import { default as ReactSelect } from 'react-select';

然后创建一个自定义组件,该组件定义一个名为“ allowSelectAll”的新属性,并在将该属性设置为“ true”时选择所有选项。

const Select = props => {
    if (props.allowSelectAll) {
        if (props.value && (props.value.length === props.options.length)) {
            return (
                <ReactSelect
                    {...props}
                    value={[props.allOption]}
                    onChange={selected => props.onChange(selected.slice(1))}
                />
            );
        }

        return (
            <ReactSelect
                {...props}
                options={[props.allOption, ...props.options]}
                onChange={selected => {
                    if (
                        selected.length > 0 &&
                        selected[selected.length - 1].value === props.allOption.value
                    ) {
                        return props.onChange(props.options);
                    }
                    return props.onChange(selected);
                }}
            />
        );
    }

    return <ReactSelect {...props} />;
};

Select.propTypes = {
    options: PropTypes.array,
    value: PropTypes.any,
    onChange: PropTypes.func,
    allowSelectAll: PropTypes.bool,
    allOption: PropTypes.shape({
        label: PropTypes.string,
        value: PropTypes.string
    })
};

Select.defaultProps = {
    allOption: {
        label: "Select all",
        value: "*"
    }
};
  

注意:您只需复制并粘贴上面给出的代码,它就可以正常工作。

完成后,您可以简单地使用新的“选择”组件,并将“ allowSelectAll”属性设置为true。

<Select allowSelectAll={true} isMulti={true} isSearchable={true} options={options} />

答案 2 :(得分:0)

我破解了我想要的东西,但是很丑陋:

https://codesandbox.io/s/j7453qrmv

要使用:

  • 尝试搜索“苹果”,然后按“将所有匹配项添加到选择中”

方法:

  • 如@wdm所述,您可以使用onInputChanged进行连接。
  • onInputChanged中,获取匹配项以组件状态存储它们
  • 我在Select附近添加了一个按钮,允许用户选择将匹配的项目集复制到另一个状态变量chosenItems
  • react-select Select组件具有一个value属性,您可以提供该属性以编程方式选择项目。我将state.chosenItems传递给了这个。

这可行,但是有很多事情使这很痛苦:

  • 与过滤器匹配的项目出现之前,将调用onInputChanged处理程序。我试图通过DOM查询来获取匹配项,但由于onInputChanged还为时过早,因此无法正常工作。因此,我不是依靠react-select的过滤逻辑,而是在onInputChanged处理程序中复制过滤逻辑。这不是很好,因为我的过滤逻辑与显示的匹配项列表之间可能会有差异。
  • 键入搜索后,无论何时单击,react-select都会清除搜索,这会再次调用onInputChanged事件。因此,通过单击自定义的“添加所有匹配项”按钮,它将删除过滤器,清除列表,调用onInputChanged并使用新的匹配项列表设置状态。为了解决这个问题,我需要有一个previousMatchingOptions状态变量,该变量跟踪先前调用onInputChanged时的匹配项。这似乎是一个可怕的骇客。
  • 同样,我试图根据当前是否有多个与搜索匹配的项目来隐藏/显示“选择所有匹配的项目”按钮,但同样由于计时问题而受到挫折。我试图解决这个问题,但一直陷入困境。
  • 我为“选择所有匹配项”设计的UI与react-select集成得不太好。如果它是它们组件的一部分而不是它的一部分,那就更好了。
  • 通过使用values组件的Select属性,您可以绕过该组件对其状态的内部管理,因此,在没有重新实现所有功能的情况下,添加,删除和清除项目的常规方法不起作用在自定义onChange处理程序中进行修改,该处理程序修改了传递到state.chosen的{​​{1}}。自己管理这似乎也不可取。

所以,我有一个解决方案,但是如果有人提出的建议更干净和/或更简单,我将很高兴听到它!

似乎分叉控件并在组件内部进行这些更改可能是更好的方法。

  • 在我的values中,我尝试使用一些onInputChanged黑客直接从DOM获取匹配的搜索结果,尽管这种方法因为getElementsByClassName
  • 而无效

答案 3 :(得分:0)

您可以像这样使用filterOption函数:

<select
  options={[{label: 'test', value: 1, customData: 'bla blub test'}]}
  filterOption={(option, filter) => {
    const { customData } = option.customData;

    if(customData.toLowerCase().indexOf(filter.toLowerCase()) >= 0) {
      return true;
    }
  }} />

希望这会对您有所帮助:)