Home > Software engineering >  MUI Select with Array of Objects as values. How to unselect predefined state?
MUI Select with Array of Objects as values. How to unselect predefined state?

Time:09-19

I have an array of object that looks like this:

[
  {
    _id: "6311c197ec3dc8c083d6b632",
    name: "Safety"
  },
........
];

I load this array as potential Menu Items for my Select:

 {categoryData &&
          categoryData.map((cat: any) => (
            <MenuItem key={cat._id} value={cat}>
              <Checkbox
                checked={categories.some((el: any) => el._id === cat._id)}
              />
              <ListItemText primary={cat.name} />
            </MenuItem>
          ))}

In my Select I have predefined value for it:

 const [categories, setCategories] = useState([
    {
      name: "Safety",
      _id: "6311c197ec3dc8c083d6b632"
    }
  ]);
.......

  <Select
        labelId="demo-multiple-checkbox-label"
        id="demo-multiple-checkbox"
        multiple
        value={categories}
        onChange={(event: any) => {
          const {
            target: { value }
          } = event;
          console.log(value);
          setCategories(value);
        }}
        input={<OutlinedInput label="Tag" />}
        renderValue={(selected) => selected.map((cat) => cat.name).join(", ")}
      >

The problem is I am unable to unselect(de-select) the predefined value. In stead of removing it from array of categories I got it once again in it.

enter image description here

Here is the sandbox example:

https://codesandbox.io/s/recursing-river-1i5jw8?file=/src/Select.tsx:632-757

I understand that values has to be exactly equal to be removed but how I can do that? What is wrong with this kind of handling?

Also I found this case as reference but still couldn't do it as in the case they use formik:

Unselect MUI Multi select with initial value

CodePudding user response:

Initially, you have to pass an empty array while setting the state. This will solve your problem.

Code changes will look like this -

const [categories, setCategories] = useState([]);

CodePudding user response:

You can't directly save the Object as the value. You must use a unique string or stringify the entire object and store it as the value. And based on that value calculate the selected value rendered text. Here is something that will work for you.

Changes: use _id as the value instead of the entire object. And added a new selected value renderer.

import {
  FormControl,
  Select,
  MenuItem,
  InputLabel,
  Checkbox,
  ListItemText,
  OutlinedInput
} from "@mui/material";
import React, { useState, useMemo } from "react";

const categoryData = [
  {
    _id: "6311c197ec3dc8c083d6b632",
    name: "Safety"
  },
  {
    _id: "6311c8e6ec3dc8c083d6b63b",
    name: "Environment"
  },
];

const SelectForm = () => {
  const [categories, setCategories] = useState(["6311c197ec3dc8c083d6b632"]);

  const selectedCategories = useMemo(() => {
    let value = "";
    categoryData.forEach((cat) => {
      if (categories.some((catId: any) => catId === cat._id)) {
        if (value) {
          value  = ", "   cat.name;
        } else {
          value = cat.name;
        }
      }
    });
    return value;
  }, [categories]);

  return (
    <FormControl fullWidth>
      <InputLabel id="demo-multiple-checkbox-label">Category</InputLabel>
      <Select
        labelId="demo-multiple-checkbox-label"
        id="demo-multiple-checkbox"
        multiple
        value={categories}
        onChange={(event: any) => {
          const {
            target: { value }
          } = event;
          console.log(value);
          setCategories(value);
        }}
        input={<OutlinedInput label="Tag" />}
        renderValue={() => selectedCategories}
      >
        {categoryData &&
          categoryData.map((cat: any) => (
            <MenuItem key={cat._id} value={cat._id}>
              <Checkbox
                checked={categories.some((catId: any) => catId === cat._id)}
              />
              <ListItemText primary={cat.name} />
            </MenuItem>
          ))}
      </Select>
    </FormControl>
  );
};

export default SelectForm;
  • Related