I want to be able to select multiple options in the dropdown, how can I change my code to do that?

Currently, my dropdown looks like this. I can only select one of the options. I want to be able to select multiple options when clicking. I tried adding multiple in <select> but that doesn't work. How can I make the dropdown allow multiple selections?

enter image description here

const SelectMultipleDropdown = props => {
  const {
    name,
    required,
    placeholder,
    handleChange,
    choices,
    value,
    fieldValid,
    setFieldValid
  } = props;
  const [currentSelection, setCurrentSelection] = useState("");

  // the default value is empty string ""
  // invalid/greyed out value is empty string ""
  return (
    <div>
      <p className="field-component-title">
        {name}
        {required ? <span className="required-star"> *</span> : ""}
      </p>
      <select 
        className={`dropdown-select-field field-component-input-box ${
          currentSelection === ""
            ? "dropdown-select-grey"
            : "dropdown-select-black"
        } ${(() => {
          return fieldValid ? "" : "dropdown-select-invalid";
        })()}`}
        type="text"
        onChange={e => {
          e.persist();
          setCurrentSelection(e.target.value);
          handleChange(e);
          setFieldValid(true);
        }}
        value={value}
      >
        <option value={""}>{placeholder}</option>
        {choices.map(({ value, text }, index) => (
          <option key={index} value={value}>
            {text}
          </option>
        ))}
      </select>
    </div>
  );
};

2 answers

  • answered 2021-11-23 01:57 Michael An

    I think in this component, your current Selection is a string, and use setCurrentSelection(e.target.value); can change currentSelection to another option.

    You can change string to array, for instance, currentSelections. And change setCurrentSelections function to:

      setCurrentSelections = (e) => {
        const value = e.target.value;
        let currentSelections = this.state.currentSelections.slice(0);
        let index = currentSelections.indexOf(value);
        if (index > -1) {
          currentSelections.splice(index, 1);
        } else {
          currentSelections.push(value);
        }
        this.setState({ currentSelections: currentSelections });
      }
    

    And use React Component

    class SelectMultipleDropdown extends React.Component {
    
      constructor(props) {
        super(props);
        this.state = {
          currentSelections: [],
        }
      }
    
      setCurrentSelections = (e) => {
        const value = e.target.value;
        let currentSelections = this.state.currentSelections.slice(0);
        let index = currentSelections.indexOf(value);
        if (index > -1) {
          currentSelections.splice(index, 1);
        } else {
          currentSelections.push(value);
        }
        this.setState({ currentSelections: currentSelections });
      }
    
      onChange = (e) => {
        e.persist();
        this.setCurrentSelection(e);
        this.porps.handleChange(e);
        this.props.setFieldValid(true);
      }
    
      render() {
        const {
          name,
          required,
          placeholder,
          choices,
          value,
        } = props;
        return (
          <div>
            <p className="field-component-title">
              {name}
              {required ? <span className="required-star"> *</span> : ""}
            </p>
            <select 
              className={''}
              type="text"
              onChange={this.onChange}
              value={value}
            >
              <option value={""}>{placeholder}</option>
              {choices.map(({ value, text }, index) => (
                <option key={index} value={value} selected={this.state.currentSelections.includes(value)}>
                  {text}
                </option>
              ))}
            </select>
          </div>
        );
      }
    }
    

  • answered 2021-11-23 04:29 DCTID

    I'm a bit unclear on the error or undesired behavior you get here. But, here's my try. First multiple works a bit weird depending on browser and OS as described here. I'm guessing that's not what you're describing tho. I'm guessing the problem is that you are 1. overwriting all your selected and 2. not mapping selected to your options. So you need to start with an empty array for your selected elements if nothing is selected, then add to that array in the onChange() instead of overwrite the value there and finally add selected to the option when it's in your list of selected elements.

    I would also add it appears you are storing the value at this level component and a higher level component thru a callback. It is generally a best practice to store the value in one spot. I'm not sure the best place from this bit of code. That might be best in another question.

      const [currentSelection, setCurrentSelection] = useState([]);
    
      return (
        <div>
          <p className="field-component-title">
            {name}
            {required ? <span className="required-star"> *</span> : ""}
          </p>
          <select 
            className={`dropdown-select-field field-component-input-box ${
              currentSelection === ""
                ? "dropdown-select-grey"
                : "dropdown-select-black"
            } ${(() => {
              return fieldValid ? "" : "dropdown-select-invalid";
            })()}`}
            type="text"
            onChange={e => {
              e.persist();
              setCurrentSelection((current) => [...current, e.target.value]);
              handleChange(e);
              setFieldValid(true);
            }}
          >
            <option value={""}>{placeholder}</option>
            {choices.map(({ value, text }, index) => (
              <option key={index} value={value} selected={currentSelection.includes(value)}>
                {text}
              </option>
            ))}
          </select>
        </div>
      );
    };
    
    

    Note: if you want to support super old browsers you'd need to replace includes(currentValue) with indexOf(currentValue) > -1

How many English words
do you know?
Test your English vocabulary size, and measure
how many words do you know
Online Test
Powered by Examplum