admin管理员组

文章数量:1327301

I need to add "Select All" option in my multi-select. It should be displayed if there is at least 1 filtered option. Click on "Select All" should then add only filtered options (not all options necessarily) to already selected options.

  1. Input is empty, so all options are "filtered":

Clicking on Select All option would then add all options to selected options.

  1. Input contains "custom", so only one option remains::

Clicking on Select All option would then add only that one option to selected options.

It was easy to add "Select all" option that adds all initial options, but that isn't the solution to my problem. I managed to partially solve my problem by manually filtering options and storing them filtered in ponent's state, but I hope there is a simpler solution.

I need to add "Select All" option in my multi-select. It should be displayed if there is at least 1 filtered option. Click on "Select All" should then add only filtered options (not all options necessarily) to already selected options.

  1. Input is empty, so all options are "filtered":

Clicking on Select All option would then add all options to selected options.

  1. Input contains "custom", so only one option remains::

Clicking on Select All option would then add only that one option to selected options.

It was easy to add "Select all" option that adds all initial options, but that isn't the solution to my problem. I managed to partially solve my problem by manually filtering options and storing them filtered in ponent's state, but I hope there is a simpler solution.

Share Improve this question edited Aug 30, 2019 at 9:21 brklja asked Aug 28, 2019 at 19:24 brkljabrklja 1473 silver badges13 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 4

I would use a bination of filterOption, InputChange and onChange props:

  • In InputChangeyou will catch the inputValue every time the user changes it and store it into the state. This value will be reused in onChange.
  • You need to change the initial filterOption to display your Select all all the time. Original logic is if inputValue is null returns true else returns true is inputValue is included in option label or value. Before doing this logic, we had an other condition where if option value corresponds to your Select all option then returns true right away.
  • In onChange; by default the returned options are those received. Then if an option has been selected (as it's multiple it could be removed) and this option is Select all, your returned value should be a copy of all the options and filter them by the inputValue.

Maybe there's a simplest way to do it but I think this one it pretty effective:

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

Below the isIncludingString function used in onChange.

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

Here a live example.

Here is the function that I used to convert all my existing multi selecters:

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

const addSelectAllOptionIfIsMulti = (props) => {
  if (!props.isMulti) {
    return props;
  }
  const selectAllOption = {}; // just an object to be pared 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;

本文标签: javascriptReactselect isMulti select all filtered optionsStack Overflow