coderX
coderX

Reputation: 223

MUIv5 AutoComplete multi select customization

I am trying to use mui Autocomplete multi select component but can't make it work as per my requirements. I want it to have default selected values which will be passed as a props from Parent component and dropdown options which I will be getting via an API.

Problem 1 : I am able to render my deafult values in input box which was passed as props but my selected values should not be there in options. Right now I can add duplicate values meaning even though I have few items selected by default in input box but still I could see them in dropdown. I have tried to read the docs it says The value must have reference equality with the option in order to be selected. but can't understand clearly. Is it because I am using 2 different states(arrays) for value and options?.

Problem 2 (Extra requirement)

In addition to the list of usersOptions that I will get from API to populate the dropdown option, I also need to add an option of All.

  1. Whenever few items are already selected and then user clicks ALL in dropdown all the selected items should be removed and only All should be there in input box and when user tries to open the dropdown, all other values should be disabled.

  2. When the user deselect ALL from the dropdown then only he/she should be able to select individual value(user)

Basically the user should be able to select only ALL or Individual user(value).

Link to CodeSanbox(https://codesandbox.io/s/naughty-elbakyan-hi16x5?file=/src/AutoComplete.js:0-1399)

import { useEffect, useState } from "react";

//This is the structure of data for both users & usersOptions
const AutoComplete = ({ users }) => {
const [selectedUsers, setSelectedUsers] = useState(users);

const [usersOptions, setUsersOptions] = useState([]);

 useEffect(() => {
 // fetch("https://x.com/api/getUsers")
 //   .then((response) => response.json())
 //   .then((data) => setUsersOptions(data));
 //let's assume API returned this
 const usersOptions = [
   { id: 1, name: "User 1" },
   { id: 2, name: "User 2" },
   { id: 3, name: "User 3" },
   { id: 4, name: "User 4" },
   { id: 5, name: "User 5" },
   { id: 6, name: "User 6" }
 ];
 const usersOptionsWithAll = [{ id: 0, name: "All" }, ...usersOptions];
 setUsersOptions(usersOptionsWithAll);
 }, []);

 console.log("selectedUsers", selectedUsers);
 console.log("usersOptions", usersOptions);

 return (
 <Autocomplete
   multiple
   id="tags-outlined"
   options={usersOptions}
   getOptionLabel={(option) => option.name}
   filterSelectedOptions
   renderInput={(params) => (
     <TextField {...params} label="" placeholder="" />
   )}
   value={selectedUsers}
   onChange={(event, newValue) => {
     setSelectedUsers(newValue);
   }}
 />
);
};

export default AutoComplete;


[1]: https://i.sstatic.net/83V7d.jpg

Upvotes: 1

Views: 1416

Answers (1)

Amr Eraky
Amr Eraky

Reputation: 1771

1. You should use isOptionEqualToValue prop to determine if the option represents the given value.
2. It is preferable to use filterOptions prop to add 'All' option or any options you want to add.

import { Autocomplete, TextField, createFilterOptions } from "@mui/material";
import { useEffect, useState } from "react";

const AutoComplete = ({ users }) => {
  const [selectedUsers, setSelectedUsers] = useState(users);
  const [usersOptions, setUsersOptions] = useState([]);

  useEffect(() => {

    const usersOptions = [
      { id: 1, name: "User 1" },
      { id: 2, name: "User 2" },
      { id: 3, name: "User 3" },
      { id: 4, name: "User 4" },
      { id: 5, name: "User 5" },
      { id: 6, name: "User 6" }
    ];
    setUsersOptions(usersOptions);    // Set options without adds
  }, []);

  return (
    <Autocomplete
      multiple
      id="tags-outlined"
      options={usersOptions}
      getOptionLabel={(option) => option.name}
      filterSelectedOptions
      renderInput={(params) => (
        <TextField {...params} label="" placeholder="" />
      )}
      value={selectedUsers}

      onChange={(event, newValue) => {
        // Check if 'All' option is clicked
        if (newValue.find(option => option.id === 0)) {
          // Check if all options are selected
          if (usersOptions.length === selectedUsers.length) {
            setSelectedUsers([]);
          } else {
            setSelectedUsers(usersOptions);
          }
        } else {
          setSelectedUsers(newValue);
        }
      }}
      // Add These props
      isOptionEqualToValue={(option, value) => option.id === value.id}
      filterOptions={(options, params) => {
        const filtered = createFilterOptions()(options, params);
        return [{ id: 0, name: 'All' }, ...filtered];
      }}
    />
  );
};

export default AutoComplete;

Mui Autocomplete API

Edit geocoding-demo (forked)

Upvotes: 1

Related Questions