11

I'm using the Material UI Autocomplete component to make an API call in a method that returns a JSON. The idea is that when the user types in the autocomplete component it makes a call to find the results matching the string.

The problem I have with the code I put is that I don't know how to make the API call and return the results in the autocomplete component

const [itemsAutocomplete, setItemsAutocomplete] = useState([])

 <Autocomplete
     disablePortal
     id="autocomplete-search"
     onChange={handleItemsOptions}
     getOptionLabel={option => option.name}
     sx={{ width: 300 }}
     renderInput={params => (
     <TextField {...params} label="Search an item..." />
     )}
     />



const handleItemsOptions = event => {

    const requestOptions = {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
            name : search_name,
        }),
    }

   
    fetch(
        `${process.env.NEXT_PUBLIC_BACKEND_URL}/api/product/items/search/`,
        requestOptions,
    )
        .then(response => response.json())
        .then(json => setItemsAutocomplete(json))
}

1 Answer 1

18

If you want to update the options every time the user types into the search box, you could use the onInputChange property of the Autocomplete and hook that up to a function which performs the API call and updates the options based on the results.

HTML

<Autocomplete
        id="combo-box-demo"
        options={options}
        onInputChange={onInputChange}
        getOptionLabel={(option) => option.title}
        style={{ width: 300 }}
        renderInput={(params) => (
          <TextField {...params} label="Combo box" variant="outlined" />
        )}
      />

Javascript

const [options, setOptions] = useState([]);
const previousController = useRef();

const getData = (searchTerm) => {
  if (previousController.current) {
    previousController.current.abort();
  }
  const controller = new AbortController();
  const signal = controller.signal;
  previousController.current = controller;
  fetch("https://dummyjson.com/products/search?q=" + searchTerm, {
    signal,
    headers: {
      "Content-Type": "application/json",
      Accept: "application/json"
    }
  })
    .then(function (response) {
      return response.json();
    })
    .then(function (myJson) {
      console.log(
        "search term: " + searchTerm + ", results: ",
        myJson.products
      );
      const updatedOptions = myJson.products.map((p) => {
        return { title: p.title };
      });
      setOptions(updatedOptions);
    });
};

const onInputChange = (event, value, reason) => {
  if (value) {
    getData(value);
  } else {
    setOptions([]);
  }
};

onInputChange will perform an HTTP request (getData(value)) if the user has typed something. If the string is empty (i.e. the user has deleted the text they typed) it will default the options to the empty array. In this function, value is the string the user has typed.

getData performs an HTTP request and calls setOptions to update the autocomplete options based on the results returned. The use of AbortController is to ensure that when the user types (or deletes) a character and the next HTTP request is made, previous HTTP requests are cancelled. This is because depending on the speed of the API, requests may not return in the order they are sent.

See this CodeSandbox for a working demo.

Sign up to request clarification or add additional context in comments.

4 Comments

Great job, but it get an error when it is working : "Error: The error you provided does not contain a stack trace."
This was VERY helpful getting me started with the autcomplete dropdown! I was fortunate enough to not get the error that Ronald got. I just got stuck briefly before importing useRef, and of course, renaming the fields.
Hi, I wrote the code like this in my project and it works fine but when I use AutoComplete with multiple option after search it rerender and empty my textfield. Any solution?
Do you realize that you can also just use the onChange prop of the input?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.