Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Material UI Autocomplete - Disable listbox after the item selection

I'm creating an Autocomplete component in React.js with the help of Material-UI headless useAutoComplete hook. The component is working properly. When the user tries to type any character, the Listbox will automatically open.

But the problem is that when the user selects anything and pays attention to the input element, the ListBox reopens. How can I prevent this?

Codesandbox:

Edit fg56t

Code:

import React from 'react';
import useAutocomplete from '@material-ui/lab/useAutocomplete';

function AutocompleteComponent(props) {
  const { data } = props;

  const [value, setValue] = React.useState('');
  const [isOpen, setIsOpen] = React.useState(false);

  const handleOpen = function () {
    if (value.length > 0) {
      setIsOpen(true);
    }
  };

  const handleInputChange = function (event, newInputValue) {
    setValue(newInputValue);
    if (newInputValue.length > 0) {
      setIsOpen(true);
    } else {
      setIsOpen(false);
    }
  };

  const {
    getRootProps,
    getInputProps,
    getListboxProps,
    getOptionProps,
    groupedOptions
  } = useAutocomplete({
    id: 'form-control',
    options: data,
    autoComplete: true,
    open: isOpen, // Manually control
    onOpen: handleOpen, // Manually control
    onClose: () => setIsOpen(false), // Manually control
    inputValue: value, // Manually control
    onInputChange: handleInputChange, // Manually control
    getOptionLabel: (option) => option.name
  });

  const listItem = {
    className: 'form-control__item'
  };

  return (
    <div className="app">
      <div className="form">
        <div {...getRootProps()}>
          <input
            type="text"
            className="form-control"
            placeholder="Location"
            {...getInputProps()}
          />
        </div>
        {groupedOptions.length > 0 && (
          <ul
            className="form-control__box"
            aria-labelledby="autocompleteMenu"
            {...getListboxProps()}
          >
            {groupedOptions.map((option, index) => {
              return (
                <li {...getOptionProps({ option, index })} {...listItem}>
                  <div>{option.name}</div>
                </li>
              );
            })}
          </ul>
        )}
      </div>
    </div>
  );
}

export default AutocompleteComponent;
like image 974
Ven Nilson Avatar asked Jul 03 '21 11:07

Ven Nilson


People also ask

How to clear the input of autocomplete?

But there is no method or properties to clear Input of AutoComplete. I got it working by using setState on the searchText property with refs as in

How does the inline completion string work with autocomplete?

The inline completion string is visually highlighted and has a selected state. If true, the first option is automatically highlighted. If true, the selected option becomes the value of the input when the Autocomplete loses focus unless the user chooses a different option or changes the character string in the input.

What is the use of ownerstate in autocomplete?

ownerState: The state of the Autocomplete component. If true, the input's text is selected on focus. It helps the user clear the selected value. The size of the component. The system prop that allows defining system overrides as well as additional CSS styles. See the `sx` page for more details.

Does autocomplete work with input props and text field props?

The autoComplete attribute of the input props and text field props are meant to follow the HTML spec. It seems to not work for some of us. Strangely, I don't see off listed in the spec but it doesn't turn it off for me while strings such as nope, nahhhh do - that is strings that aren't in the spec.


1 Answers

You can store the selectedItem in a state and use it in handleOpen to decide whether the list has to be displayed. For setting selectedItem you can modify the default click provided by getOptionProps

import React from 'react';
import useAutocomplete from '@material-ui/lab/useAutocomplete';

function AutocompleteComponent(props) {
  const { data } = props;

  const [value, setValue] = React.useState('');
  const [isOpen, setIsOpen] = React.useState(false);
  const [selectedItem, setSelectedItem] = React.useState('');

  const handleOpen = function () {
    if (value.length > 0 && selectedItem !== value) {
      setIsOpen(true);
    }
  };

  const handleInputChange = function (event, newInputValue) {
    setValue(newInputValue);
    if (newInputValue.length > 0) {
      setIsOpen(true);
    } else {
      setIsOpen(false);
    }
  };

  const {
    getRootProps,
    getInputProps,
    getListboxProps,
    getOptionProps,
    groupedOptions
  } = useAutocomplete({
    id: 'form-control',
    options: data,
    autoComplete: true,
    open: isOpen, // Manually control
    onOpen: handleOpen, // Manually control
    onClose: () => setIsOpen(false), // Manually control
    inputValue: value, // Manually control
    onInputChange: handleInputChange, // Manually control
    getOptionLabel: (option) => option.name
  });

  const listItem = {
    className: 'form-control__item'
  };

  return (
    <div className="app">
      <div className="form">
        <div {...getRootProps()}>
          <input
            type="text"
            className="form-control"
            placeholder="Location"
            {...getInputProps()}
          />
        </div>
        {groupedOptions.length > 0 && (
          <ul
            className="form-control__box"
            aria-labelledby="autocompleteMenu"
            {...getListboxProps()}
          >
            {groupedOptions.map((option, index) => {
              return (
                <li
                  {...getOptionProps({ option, index })}
                  {...listItem}
                  onClick={(ev) => {
                    setSelectedItem(option.name);
                    getOptionProps({ option, index }).onClick(ev);
                  }}
                >
                  <div>{option.name}</div>
                </li>
              );
            })}
          </ul>
        )}
      </div>
    </div>
  );
}

export default AutocompleteComponent;

Edited

like image 174
Anish Antony Avatar answered Oct 17 '22 20:10

Anish Antony