6

I want to use an Autocomplete (from the Material-Ui library) component from material ui to select multiple options, and those options should not be able to be removed (directly) by the user.

The problem I'm facing is that the user can delete the options from the Autocomplete if they focus the component and press backspace as if they are deleting text.

Code

This is the component I'm using:

<Autocomplete multiple
    options={options}
    getOptionLabel={option => option.title}
    renderInput={params =>
        <TextField {...params} label="Autocomplete" variant="outlined" />
    }
    onChange={this.onAutocompleteChange.bind(this)}
    getOptionSelected={(option: Option, value: Option) => option.value === value.value}
    filterSelectedOptions={true}
    renderTags={(tagValue, getTagProps) =>
        tagValue.map((option, index) => (
            <Chip key={option.value} label={option.title} color="primary" />
        ))
    }
    disableClearable={true}
/>

What I tried

  • Disabling the TextField from the renderInput prop with disable={true} has no effect.
  • Adding InputProps={{ disabled: true }} or InputProps={{ readOnly: true }} to TextField disables the Autocomplete completely.
  • Adding ChipProps={{ disabled: true }} to the Autocomplete has no effect.

Thanks for reading!

LeonMarchetti
  • 105
  • 3
  • 9

1 Answers1

5

To control this aspect, you need to use a controlled approach to the Autocomplete's value as demonstrated in this demo.

In the documentation for the onChange prop you will find the following:

onChange    Callback fired when the value changes.

Signature:

function(event: object, value: T | T[], reason: string) => void

   event: The event source of the callback.
   value: The new value of the component.
   reason: One of "create-option", "select-option", "remove-option", "blur" or "clear".

The third argument to onChange is the "reason" for the change. In your case, you want to ignore all of the "remove-option" changes:

        onChange={(event, newValue, reason) => {
          if (reason !== "remove-option") {
            setValue(newValue);
          }
        }}

Here's a full working example:

import React from "react";
import TextField from "@material-ui/core/TextField";
import Autocomplete from "@material-ui/lab/Autocomplete";
import Chip from "@material-ui/core/Chip";

const options = ["Option 1", "Option 2"];

export default function ControllableStates() {
  const [value, setValue] = React.useState([options[0]]);
  const [inputValue, setInputValue] = React.useState("");

  return (
    <div>
      <div>{`value: ${value !== null ? `'${value}'` : "null"}`}</div>
      <div>{`inputValue: '${inputValue}'`}</div>
      <br />
      <Autocomplete
        multiple
        value={value}
        disableClearable
        onChange={(event, newValue, reason) => {
          if (reason !== "remove-option") {
            setValue(newValue);
          }
        }}
        inputValue={inputValue}
        onInputChange={(event, newInputValue) => {
          setInputValue(newInputValue);
        }}
        id="controllable-states-demo"
        options={options}
        style={{ width: 300 }}
        renderInput={params => (
          <TextField {...params} label="Controllable" variant="outlined" />
        )}
        renderTags={(tagValue, getTagProps) =>
          tagValue.map((option, index) => (
            <Chip key={option} label={option} color="primary" />
          ))
        }
      />
    </div>
  );
}

Edit Autocomplete ignore remove-option changes

Ryan Cogswell
  • 75,046
  • 9
  • 218
  • 198