reactjstypescriptmaterial-ui

Displaying an option's Name rather than ID in a MUI multi-select dropdown's renderValue


I am working with a MUI multi-select dropdown and I am struggling the get the renderValue to populate a comma-separated list of the selected options' names. The example from the MUI website ends up displaying a comma-separated list of the options' IDs since it seems to used the value as the basis of the renderValue.

The easiest was to accomplish this would be to change value={option.id} to value={option.name}, but that causes an issue because I need to use the ID as the value so I can write it back the DB, not the name.

I have tried writing functions to compare the selected against the array of options and grab the name of the object with an ID matching one of the selected but couldn't get it to work, especially since I couldn't seem to access selected outside of the renderValue prop. Can someone please show me how to display the name instead of the ID in the renderValue?

Here is an example my options:

[
  {
   "id": 1,
   "name": "Option-1"
  },
  {
   "id": 2,
   "name": "Option-2"
  },
    {
   "id": 3,
   "name": "Option-3"
  }
 ]

Currently the renderValue displays 1, 2, 3 when the dropdown is closed, but I would like to display Option-1, Option-2, Option-3 since the IDs have no significance to the user.

Here is my component:

import * as React from 'react';
import axios from 'axios';
import { Checkbox, FormControl, FormHelperText, InputLabel, Select, MenuItem, ListItemText, OutlinedInput } from '@material-ui/core';

export default function dropdownMultiSelect(props) {
  const { label, name, onChange, prompt, value, url } = props;
  const [options, setOptions] = React.useState([]); // populated by Axios call

  return (
      <FormControl >
        <InputLabel>{label}</InputLabel>
        <Select
          multiple
          name={name}
          value={(value === undefined || value === null || options.length === 0) ? '' : value} 
          onChange={onChange}
          // renderValue={(selected) => selected.join(', ')} 
          renderValue={(selected) => {
               const selectedOption = options.filter((option) => 
               selected.includes(option.id)).map((option) => option.name);
               return selectedOption.join(', '); }
          }
        >
          {options.map((option) => (
            <MenuItem 
              key={option.id}
              value={option.id}
            >
            <Checkbox 
              checked={value.includes(option.id)}
            />
            {option.name}
            </MenuItem>
          ))}
        </Select> 
      </FormControl>
  );
}

Here is my change handler

  const [values, setValues] = React.useState({} as any);

  const handleInputChange = e => {
    const { name, value } = e.target;
    setValues({
      ...values,
      [name]: value
    });
    if (validateOnChange) { validate({ [name]: value }); }
  };

Solution

  • A solution has been found, so I want to share it for others so then don't have to spend as much time searching for a solution as I did.

    This is the example from the MUI website. This will display a comma-separated list using the value of your MenuItem, in the example above it would be the option.id as designated value={option.id}

    renderValue={(selected) => selected.join(', ')} 
    

    I needed to pass the ID back as a my value, rather than the name, so to be able to use something other than what is designated in the value prop, it required creating a filter and mapping through the options array which populate the dropdown to fetch the name.

    This will allow you to use the option.name rather the value of option.id

    renderValue={(selected) => {
        const selectedOption = options.filter((option) => 
        selected.includes(option.id)).map((option) => option.name);
        return selectedOption.join(', '); }
    }