Home > Enterprise >  How can I display maximum item selected once i have selected 3 items from dropdown
How can I display maximum item selected once i have selected 3 items from dropdown

Time:10-27

I have multiselect dropdown items with checkboxes in my react app, what I am trying to achieve is if I checked any three items, then dropdown should display maximum items selected and if I unchecked anyone of them, it should display back the drop down box with items. Somehow it doesn't work, could someone please advise.

CodeSanbox link

https://codesandbox.io/s/musing-sun-swvj6y?file=/src/App.js

import { useState } from "react";
import Multiselect from "multiselect-react-dropdown";
import "./styles.css";

export default function App() {
  const options = [
    { key: "Apple", email: "[email protected]", id: 1 },
    { key: "Orange", email: "[email protected]", id: 2 },
    { key: "Mango", email: "[email protected]", id: 3 },
    { key: "Grapes", email: "[email protected]", id: 4 }
  ];

  const [option, setOption] = useState([]);
  const [selectedOption, setSelectedOption] = useState([]);
  const [maxOptions, setMaxOptions] = useState(0);

  const handleTypeSelect = (e, i) => {
    const copy = [...selectedOption];
    copy.push(e[3 - maxOptions]);
    setSelectedOption(copy);
    setMaxOptions((prevState) => prevState - 1);
  };

  const handleTypeRemove = (e) => {
    const copy = [...selectedOption];
    let index = copy.indexOf(e);
    copy.splice(index, 1);
    setSelectedOption(copy);
    setMaxOptions((prevState) => prevState   1);
  };

  options.forEach((option) => {
    option.displayValue = option.key   "\t"   option.email;
  });

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <Multiselect
        onSelect={(e) => handleTypeSelect(e, selectedOption.length)}
        onRemove={handleTypeRemove}
        options={selectedOption.length   1 === maxOptions ? [] : options}
        // options={!showOptions ? [] : option}
        displayValue="displayValue"
        showCheckbox={true}
        emptyRecordMsg={"Maximum fruits selected !"}
      />
    </div>
  );
}

CodePudding user response:

The library doesn't support manually selecting/deselecting the options. Reference

There is one hack that you can do. You can play around with key. Use the selectedItems as key and then it will re-mount the component whenever the selectedItems changes.

Note that this hack is not the recommended way to do "React".

You update the options based on the size of the selected options

const maxSelectableItems = 3;

const options = [
  { key: "Apple", email: "[email protected]", id: 1 },
  { key: "Orange", email: "[email protected]", id: 2 },
  { key: "Mango", email: "[email protected]", id: 3 },
  { key: "Grapes", email: "[email protected]", id: 4 }
];

<Multiselect
  // This will re-mount your component whenever 
  // selected items changes
  key={selectedItems} 

  onSelect={handleSelection}
  onRemove={handleRemove}

  // This will set the pre-selected values on re-mount
  selectedValues={selectedItems}

  options={
  selectedItems.length === maxSelectableItems 
    ? [] 
    : options.map((o) => ({ 
      ...o, 
      displayValue:  `${o.key}\t${o.email}`
    }))
  }
  displayValue="displayValue"
  showCheckbox
  emptyRecordMsg={"Maximum fruits selected !"}
/>

And, your handleSelection and handleRemove will look like this:

const [selectedItems, setSelectedItems] = useState([]);

const handleSelection = (selectedItems) => {
  setSelectedItems(selectedItems.slice(0, maxSelectableItems));
};

const handleRemove = (selectedItems) => {
  setSelectedItems(selectedItems);
};

One issue with this is that since it re-mounts the entire multi-select component, when you select/remove an item, the input will lose focus. So, you will have to manually give focus to the input after selection/removal.

const focusOnInput = () => {
  setTimeout(() => {
    // You can use a better selector (this is just a generic input selector)
    document.querySelector("input").focus();
  
  // Adding some delay to allow the component to re-mount
  }, 10);
};

And then, use this in your selection/removal handlers

const handleSelection = (selectedItems) => {
  setSelectedItems(selectedItems.slice(0, maxSelectableItems));
  focusOnInput()
};

const handleRemove = (selectedItems) => {
  setSelectedItems(selectedItems);
  focusOnInput()
};

Here is a link to a working sandbox

CodePudding user response:

import { useState } from "react";
import Multiselect from "multiselect-react-dropdown";
import "./styles.css";

export default function App() {
  const options = [
    { key: "Apple", email: "[email protected]", id: 1 },
    { key: "Orange", email: "[email protected]", id: 2 },
    { key: "Mango", email: "[email protected]", id: 3 },
    { key: "Grapes", email: "[email protected]", id: 4 }
  ];

  const [option, setOption] = useState([]);
  const [selectedOption, setSelectedOption] = useState([]);
  const [maxOptions, setMaxOptions] = useState(0);

  options.forEach((option) => {
    option.displayValue = option.key   "\t"   option.email;
  });

  return (
    <div className="App">
      <h1>Hello CodeSandbox2</h1>
      <Multiselect
        options={options}
        displayValue="displayValue"
        showCheckbox={true}
        selectionLimit={3}
        emptyRecordMsg={"Maximum fruits selected !"}
      />
    </div>
  );
}
  • Related