Material UI select multiple component using an object in the value property, adds duplicate entry

Viewed 6150

I have a multi select that i pass an object into the value property with the structure:

enter image description here

The select component looks like this:

<Select
            multiple
            value={entities}
            onChange={handleChange}
            input={<Input />}
            renderValue={(selected) => (
              <div className={classes.chips}>
                {selected.map((value) => (
                  <Chip
                    key={value.entityId}
                    label={value.entityName}
                    className={classes.chip}
                  />
                ))}
              </div>
            )}
          >
            {props.entityList.map((item, index) => (
              <MenuItem key={item.entityId} value={item}>
                {item.entityName}
              </MenuItem>
            ))}
          </Select>

when the select pops up it shows the entity name correct but does not show it as selected in the dropdown.

If i select this item in the drop down it adds another entry which has the same id and same name rather than removing the item that is already there, this newly added duplicate can be removed and is highlighted when selected so the functionality works somewhat.

I am storing entities in the state like so that comes in from a parent component:

enter image description here

Solution:

I have made sure that the same object is being used across the select, the initial object was not the same as the objects that where being assigned in the on Change function. this fixed my problem.

const [entities, setEntity] = React.useState(
props.entityList.filter((e) =>
  props.assignedEntities.some((ae) => e.entityId === ae.entityId)
)

);

1 Answers

I had exact problem and I solved it in the following way.

In my example I'm using role to user assignment:

Here is my role object:

Role
-----
id,
name,
access,
createdUtc

My component receives these props:

allRoles
user // that has user.roles

Here I extract only ids of the roles:

 const [selectedRoleIds, setSelectedRoleIds] = useState([]);

 useEffect(() => {
    if(user) {
      setSelectedRoleIds(user.roles.map(i => i.id));
    }

 }, [user]);

My multi select component:

<Select
    multiple
    value={selectedRoleIds}
    onChange={handleRoleChange}
    input={<OutlinedInput id="select-multiple-chip" label="Chip" />}
    renderValue={(selected) => (
    <Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.5 }}>
        {selected.map((roleId) => (
        <Chip key={roleId} label={allRoles?.find(e => e.id === roleId).name} />
        ))}
    </Box>
    )}
    MenuProps={MenuProps}
>
    {roles.map((role) => (
    <MenuItem key={role.id} value={role.id}>
        <Checkbox checked={selectedRoleIds.includes(role.id)} />
        <ListItemText primary={role.name} />
    </MenuItem>
    ))}                      
</Select>

Handling role change is easy as:

  const handleRoleChange = (event) => {
    const {value} = event.target;
    setSelectedRoleIds(value);

  };

enter image description here

Related