Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add autocomplete with multiple and creatable reactjs material ui

I want the users to be able to select multiple tags while also allowing them to add a tag if it does not exist, the examples on the material UI documentation work on the freeSolo option which works on string / object values as options whereas when we use multiple, that changes to an array

How do I implement a multiple creatable with material-ui?

My code:

// Fetch Adding tag list
const [listOpen, setListOpen] = useState(false);
const [options, setOptions] = useState<Tag[]>([]);
const loadingTags = listOpen && options.length === 0;

useEffect(() => {
  let active = true;

  if (!loadingTags) {
    return undefined;
  }

  (async () => {
    try {
      const response = await getAllTagsForUser();
      if (active) {
        setOptions(response.data);
      }
    } catch (error) {
      console.log(error);
    }
  })();

  return () => {
    active = false;
  };
}, [loadingTags]);

useEffect(() => {
  if (!listOpen) {
    setOptions([]);
  }
}, [listOpen]);


<Autocomplete
  multiple
  id="tags"
  open={listOpen}
  onOpen={() => {
    setListOpen(true);
  }}
  onClose={() => {
    setListOpen(false);
  }}
  options={options}
  disableCloseOnSelect
  getOptionLabel={(option) => option?.name || ""}
  defaultValue={
    contact?.tags?.map((element) => {
      return { name: element };
    }) || undefined
  }
  renderOption={(option, { selected }) => (
    <React.Fragment>
      <Checkbox
        icon={icon}
        checkedIcon={checkedIcon}
        style={{ marginRight: 8 }}
        checked={selected}
      />
      {option.name}
    </React.Fragment>
  )}
  style={{ width: 500 }}
  renderInput={(params) => (
    <TextField {...params} variant="outlined" label="Tags" />
  )}
/>;

This is just fetching tags from the server and showing them as options, I understand that to be able to allow adding more, I would need to add filterOptions and onChange but, can someone please provide an example on how to deal with array there?

like image 533
Amartya Gaur Avatar asked Oct 23 '25 02:10

Amartya Gaur


1 Answers

I know this isn't an quick answer but may someone else could use it. Found this Question buy searching an solution. Didn't find one so I tryed myself and this is what I Created and seems it works.

Based on the original Docs https://mui.com/components/autocomplete/#creatable

Complete example:

import React, { useEffect, useState } from "react";

//Components 
import TextField from "@mui/material/TextField";
import Autocomplete, { createFilterOptions } from "@mui/material/Autocomplete";

//Icons

const filter = createFilterOptions();

export default function AutocompleteTagsCreate() {
    const [selected, setSelected] = useState([])
    const [options, setOptions] = useState([]);

    useEffect(() => {
        setOptions(data);
    }, [])

    return (
        <Autocomplete
            value={selected}
            multiple
            onChange={(event, newValue, reason, details) => {
                let valueList = selected;
                if (details.option.create && reason !== 'removeOption') {
                    valueList.push({ id: undefined, name: details.option.name, create: details.option.create });
                    setSelected(valueList);
                }
                else {
                    setSelected(newValue);
                }
            }}
            filterSelectedOptions
            filterOptions={(options, params) => {
                const filtered = filter(options, params);

                const { inputValue } = params;
                // Suggest the creation of a new value
                const isExisting = options.some((option) => inputValue === option.name);
                if (inputValue !== '' && !isExisting) {
                    filtered.push({
                        name: inputValue,
                        label: `Add "${inputValue}"`,
                        create: true
                    });
                }

                return filtered;
            }}
            selectOnFocus
            clearOnBlur
            handleHomeEndKeys
            id="tags-Create"
            options={options}
            getOptionLabel={(option) => {
                // Value selected with enter, right from the input
                if (typeof option === 'string') {
                    return option;
                }
                // Add "xxx" option created dynamically
                if (option.label) {
                    return option.name;
                }
                // Regular option
                return option.name;
            }}
            renderOption={(props, option) => <li {...props}>{option.create ? option.label : option.name}</li>}
            freeSolo
            renderInput={(params) => (
                <TextField {...params} label="Tags" />
            )}
        />
    );
}

const data = [
    {
        id: 1,
        name: 'Tag1'
    },
    {
        id: 2,
        name: 'Tag2'
    },
    {
        id: 3,
        name: 'Tag3'
    },
    {
        id: 4,
        name: 'Tag4'
    },
]
like image 57
4Source Avatar answered Oct 27 '25 03:10

4Source



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!