React-select isMulti select 所有过滤选项

React-select isMulti select all filtered options

我需要在我的 multi-select 中添加 "Select All" 选项。如果至少有 1 个筛选选项,则应显示它。单击 "Select All" 应该只添加过滤选项(不一定是所有选项)到已经 selected 选项

  1. 输入为空,所以所有选项都是"filtered":

单击 Select 所有选项然后会将所有选项添加到 selected 选项。

  1. 输入包含"custom",所以只剩下一个选项::

单击 Select 所有选项将仅向 selected 选项添加一个选项。

添加添加所有初始选项的 "Select all" 选项很容易,但这不是我的问题的解决方案。我设法通过手动过滤选项并将它们存储在组件状态中来部分解决我的问题,但我希望有一个更简单的解决方案。

我会结合使用 filterOptionInputChangeonChange 道具:

  • InputChange 中,每次用户更改它时您都会捕获 inputValue 并将其存储到状态中。此值将在 onChange.
  • 中重复使用
  • 您需要更改初始 filterOption 以始终显示您的 Select all。原始逻辑是 if inputValue is null returns true else returns true is inputValue 包含在选项标签或值中。在执行此逻辑之前,我们有另一个条件,如果选项值对应于您的 Select all 选项,则立即 returns true
  • onChange;默认情况下,返回的选项是收到的选项。然后,如果选择了一个选项(因为它是多个可以删除)并且此选项是 Select all,您返回的值应该是所有选项的副本并按 inputValue.[= 过滤它们48=]

也许有一种最简单的方法,但我认为这个方法非常有效:

onChange = (opt, { option }) => {
  let newOpts = opt;
  let string = this.state.searchField;

  if (option && option.value === "all") {
    let filteredOptions = clone(options);

    filteredOptions = filteredOptions.filter(
      filteredOption =>
        isIncludingString(string, filteredOption) &&
        !newOpts.includes(filteredOption)
    );

    string = null;
    newOpts = newOpts
      .concat(filteredOptions)
      .filter(newOpt => newOpt.value !== "all");
  }
  this.setState({
    searchField: string,
    values: newOpts
  });
};

onInputChange = (string, { action }) => {
  if (action === "input-change") {
    this.setState({
      searchField: string
    });
  }
};  

filterOption = ({ label, value }, string) => {
  if (value === "all") {
    return true;
  } else if (string) {
    return label.includes(string) || value.toString().includes(string);
  } else {
    return true;
  }
};

Important note, in my example I use clone from lodash

onChange中使用的isIncludingString函数下方。

function isIncludingString(string, option) {
  let result = false;
  if (
    !string ||
    option.label.toString().includes(string) ||
    option.value.toString().includes(string)
  ) {
    result = true;
  }
  return result;
}

这里是live example.

这是我用来转换所有现有多重选择器的函数:

import React from "react";
import ReactSelect from "react-select";

const addSelectAllOptionIfIsMulti = (props) => {
  if (!props.isMulti) {
    return props;
  }
  const selectAllOption = {}; // just an object to be compared to by reference

  const getOptionLabel = (obj) =>
    obj === selectAllOption
      ? "Select all"
      : props.getOptionLabel
      ? props.getOptionLabel(obj)
      : obj.label;

  const getOptionValue = (obj) =>
    obj === selectAllOption
      ? selectAllOption
      : props.getOptionValue
      ? props.getOptionValue(obj)
      : obj.value;

  const onChange = (values) => {
    const selectedOptions = values.includes(selectAllOption)
      ? props.options
      : values;
    props.onChange(selectedOptions);
  };

  const options =
    props.options.length === props.value?.length
      ? props.options
      : [selectAllOption, ...props.options];

  return { ...props, getOptionLabel, getOptionValue, onChange, options };
};

function Select({...props}){
  return <ReactSelect {...addSelectAllOptionIfIsMulti(props)}/>
}
export default Select;