# MUI Autocomplete Multi-Select

**URL:** <https://jsonforms.discourse.group/t/mui-autocomplete-multi-select/1105>\
**Category:** General\
**Created:** [November 1, 2022, 2:40pm UTC](https://jsonforms.discourse.group/t/mui-autocomplete-multi-select/1105 "2022-11-01T14:40:51Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![richkroll](https://yyz2.discourse-cdn.com/free1/user_avatar/jsonforms.discourse.group/richkroll/32/512_2.png) [@richkroll](https://jsonforms.discourse.group/u/richkroll)\
**Post date:** [November 1, 2022, 2:40pm UTC](https://jsonforms.discourse.group/t/mui-autocomplete-multi-select/1105/1 "2022-11-01T14:40:51Z")

</div>

Hello all!

I am working to build a MUI Autocomplete control which supports multiple selections. I have the control rendering successfully in within JSONForms, but I am having an issue with the initial data binding. When I attempt to pass in the pre-selected enum values, I am passed the raw value, but when it is binding it is evaluating against the options in the select list. I’ve tried mapping the items but cannot seem to get them to bind correctly. Any help would be appreciated. Below is my current control. I am hoping I am missing something simple! Thanks in advance.

```auto
import merge from 'lodash/merge';
import {
  ControlProps,
  OwnPropsOfEnum,
  WithClassname,
  EnumOption,
  isDescriptionHidden,
} from '@jsonforms/core';
import { Autocomplete, FormHelperText, Hidden, TextField } from '@mui/material';
import { WithOptionLabel } from '@jsonforms/material-renderers/lib/mui-controls/MuiAutocomplete';
import { useFocus } from '@jsonforms/material-renderers';

export const MultiSelectEnumArray = (
  props: ControlProps & OwnPropsOfEnum & WithClassname & WithOptionLabel
) => {
  const [focused, onFocus, onBlur] = useFocus();
  const {
    description,
    className,
    config,
    id,
    label,
    required,
    errors,
    data,
    visible,
    options,
    handleChange,
    path,
    enabled,
    getOptionLabel,
  } = props;

  const isValid = errors.length === 0;
  const appliedUiSchemaOptions = merge({}, config, props.uischema.options);

  const showDescription = !isDescriptionHidden(
    visible,
    description,
    focused,
    appliedUiSchemaOptions.showUnfocusedDescription
  );

  const firstFormHelperText = showDescription
    ? description
    : !isValid
    ? errors
    : null;
  const secondFormHelperText = showDescription && !isValid ? errors : null;

  const onChange = (_ev: any, value: EnumOption[]) => {
    var values: EnumOption[] = [];

    value.forEach((el) => {
      values.push(el.value);
    });

    return handleChange(path, values);
  };

  return (
    <Hidden xsUp={!visible}>
      <Autocomplete
        id={id}
        multiple
        className={className}
        disabled={!enabled}
        autoHighlight
        autoSelect
        autoComplete
        fullWidth
        getOptionLabel={getOptionLabel || ((option) => option?.label)}
        freeSolo={false}
        options={options ? options : []}
        onChange={onChange}
        renderInput={(params) => {
          return (
            <TextField
              label={label}
              variant={
                appliedUiSchemaOptions.variant
                  ? appliedUiSchemaOptions.variant
                  : 'outlined'
              }
              inputRef={params.InputProps.ref}
              autoFocus={appliedUiSchemaOptions.focus}
              {...params}
              id={id + '-input'}
              required={
                required && !appliedUiSchemaOptions.hideRequiredAsterisk
              }
              error={!isValid}
              fullWidth={!appliedUiSchemaOptions.trim}
              InputLabelProps={data ? { shrink: true } : undefined}
              onFocus={onFocus}
              onBlur={onBlur}
              focused={focused}
            />
          );
        }}
      />
      <FormHelperText error={!isValid && !showDescription}>
        {firstFormHelperText}
      </FormHelperText>
      <FormHelperText error={!isValid}>{secondFormHelperText}</FormHelperText>
    </Hidden>
  );
};

```

---

<div class="post-metadata">

**Author:** ![richkroll](https://yyz2.discourse-cdn.com/free1/user_avatar/jsonforms.discourse.group/richkroll/32/512_2.png) [@richkroll](https://jsonforms.discourse.group/u/richkroll)\
**Post date:** [November 2, 2022, 6:09pm UTC](https://jsonforms.discourse.group/t/mui-autocomplete-multi-select/1105/2 "2022-11-02T18:09:58Z")

</div>

Hey All! I was able to successfully get the enum values to bind bi-directionally, but have now run into an issue with ajv failing the validation. When I inspect the values being passed for validation, an array of selected enum values is being validated (e.g. [2020,2021]) against the array provided in the schema and failing. Does anyone have an idea on what changes are needed for the control(s) to pass validation?

schema.json:

```auto
{
  "type": "object",
  "properties": {
    "multiSelectEnumArray_2": {
      "type": "array",
      "items": {
        "type": "integer"
      },
      "enum": [2022, 2021, 2020, 2019, 2018, 2017, 2016, 2015]
    }
  }
}

```

uischema.json:

```auto
{
  "type": "VerticalLayout",
  "elements": [
    {
      "type": "Control",
      "scope": "#/properties/multiSelectEnumArray",
      "options": {
        "format": "multi"
      }
    }
  ]
}

```

MultiSelectEnumArrayControl.tsx:

```auto
import {
  and,
  ControlProps,
  isEnumControl,
  optionIs,
  OwnPropsOfEnum,
  RankedTester,
  rankWith,
} from '@jsonforms/core';
import { withJsonFormsEnumProps } from '@jsonforms/react';
import { MultiSelectEnumArray } from './MultiSelectEnumArray';

export const MultiSelectEnumArrayControl = (
  props: ControlProps & OwnPropsOfEnum
) => {
  return <MultiSelectEnumArray {...props} />;
};

export const multiSelectEnumArrayControlTester: RankedTester = rankWith(
  20,
  and(isEnumControl, optionIs('format', 'multi'))
);
export default withJsonFormsEnumProps(MultiSelectEnumArrayControl);

```

MultiSelectEnumArray.tsx:

```auto
import merge from 'lodash/merge';
import isEqual from 'lodash/isEqual';
import {
  ControlProps,
  OwnPropsOfEnum,
  WithClassname,
  EnumOption,
  isDescriptionHidden,
} from '@jsonforms/core';
import { Autocomplete, FormHelperText, Hidden, TextField } from '@mui/material';
import { WithOptionLabel } from '@jsonforms/material-renderers/lib/mui-controls/MuiAutocomplete';
import { useFocus } from '@jsonforms/material-renderers';

export const MultiSelectEnumArray = (
  props: ControlProps & OwnPropsOfEnum & WithClassname & WithOptionLabel
) => {
  const [focused, onFocus, onBlur] = useFocus();
  const {
    description,
    className,
    config,
    id,
    label,
    required,
    errors,
    data,
    visible,
    options,
    handleChange,
    path,
    enabled,
    getOptionLabel,
  } = props;

  const isValid = errors.length === 0;
  const appliedUiSchemaOptions = merge({}, config, props.uischema.options);

  const showDescription = !isDescriptionHidden(
    visible,
    description,
    focused,
    appliedUiSchemaOptions.showUnfocusedDescription
  );

  const firstFormHelperText = showDescription
    ? description
    : !isValid
    ? errors
    : null;
  const secondFormHelperText = showDescription && !isValid ? errors : null;

  const onChange = (_ev: any, newValues: EnumOption[]) => {
    // convert from an EnumOption to its value
    var values = newValues.map((o) => (o.value ? o.value : o));
    handleChange(path, values);
  };

  return (
    <Hidden xsUp={!visible}>
      <Autocomplete
        multiple
        id={id}
        className={className}
        disabled={!enabled}
        autoHighlight
        autoSelect
        autoComplete
        fullWidth
        freeSolo={false}
        options={options ? options : []}
        value={data}
        getOptionLabel={(option) => (option.label ? option.label : option)}
        onChange={onChange}
        isOptionEqualToValue={(o, v) => {
          return isEqual(o.value, v);
        }}
        renderInput={(params) => (
          <TextField
            label={label}
            variant={
              appliedUiSchemaOptions.variant
                ? appliedUiSchemaOptions.variant
                : 'outlined'
            }
            inputRef={params.InputProps.ref}
            autoFocus={appliedUiSchemaOptions.focus}
            placeholder='Favorites'
            {...params}
            id={id + '-input'}
            required={required && !appliedUiSchemaOptions.hideRequiredAsterisk}
            error={!isValid}
            fullWidth={!appliedUiSchemaOptions.trim}
            InputLabelProps={data ? { shrink: true } : undefined}
            onFocus={onFocus}
            onBlur={onBlur}
            focused={focused}
          />
        )}
      />
      <FormHelperText error={!isValid && !showDescription}>
        {firstFormHelperText}
      </FormHelperText>
      <FormHelperText error={!isValid}>{secondFormHelperText}</FormHelperText>
    </Hidden>
  );
};

```

---

<div class="post-metadata">

**Author:** ![sdirix](https://yyz2.discourse-cdn.com/free1/user_avatar/jsonforms.discourse.group/sdirix/32/1073_2.png) [@sdirix](https://jsonforms.discourse.group/u/sdirix)\
**Post date:** [November 8, 2022, 7:57pm UTC](https://jsonforms.discourse.group/t/mui-autocomplete-multi-select/1105/3 "2022-11-08T19:57:49Z")

</div>

Hi @richkroll,

The JSON Schema seems to be inconsistent. It looks like this:

```auto
      "type": "array",
      "items": {
        "type": "integer"
      },
      "enum": [2022, 2021, 2020, 2019, 2018, 2017, 2016, 2015]

```

- `type: 'array'` declares the value to be an array
- However `enum: [2022, 2021 ....]` defines the value to be a number

Both constraints can never be fulfilled at the same time, so you will always have a validation error.

Probably you want to move the `enum` into the `items` to declare that only these values are allowed within the array. So you might want to try the following:

```auto
      "type": "array",
      "items": {
        "type": "integer",
        "enum": [2022, 2021, 2020, 2019, 2018, 2017, 2016, 2015]
      },

```

Does this solve your problem?

---

<div class="post-metadata">

**Author:** ![richkroll](https://yyz2.discourse-cdn.com/free1/user_avatar/jsonforms.discourse.group/richkroll/32/512_2.png) [@richkroll](https://jsonforms.discourse.group/u/richkroll)\
**Post date:** [November 9, 2022, 12:55pm UTC](https://jsonforms.discourse.group/t/mui-autocomplete-multi-select/1105/4 "2022-11-09T12:55:04Z")

</div>

Thanks @sdirix! I initially misunderstood the JSON Schema. That was indeed the missing part, thanks!

---

<div class="post-metadata">

**Author:** ![clysss](https://yyz2.discourse-cdn.com/free1/user_avatar/jsonforms.discourse.group/clysss/32/996_2.png) [@clysss](https://jsonforms.discourse.group/u/clysss)\
**Post date:** [June 30, 2024, 10:00am UTC](https://jsonforms.discourse.group/t/mui-autocomplete-multi-select/1105/5 "2024-06-30T10:00:07Z")

</div>

hello @Richkroll, could you post somewhere your component that we can reuse it ?  
Thanks !
