Add autosuggest to TagsInput

Viewed 132

To write the site, I use JavaScript, the React framework, and the library mui.

On my site, one of the input fields for the user is done using TagsInput. Thus, the user can enter data, press enter, see the tag, and optionally delete it.

For TagsInput, I did not use libraries, but wrote the code myself. It will be presented below.

I would like to improve the functionality for the user and add a predictive search (autofill). That is, when the user begins to enter letters (let it be, for example, car brands), if the car brand is currently in the database (not to complicate things, you can make a regular list or other convenient type of data), the user will be offered options for autofill.

For example: the user clicks on the field for entering a tag and enters the first letter "A" and prompts are given to him - Alfa Romeo, Aston Martin. If the Audi is not currently in the database, then the Audi tooltip will not pop up.

I will be glad for any help.

FilterMarkAuto.jsx

export default function FilterMarkAuto({ isExpanded, setIsExpanded }){
const [values, setValues] = useState([]);

return (
    <ArrowDropdown
        isExpanded={isExpanded}
        setIsExpanded={setIsExpanded}
        title="Name car"
        onClick={() => setIsExpanded(!isExpanded)}>
            
        {isExpanded && 
            <TagsInput tags={values} 
                       setTags={setValues} 
                       inputPlaceholder="Enter a car" />}
    </ArrowDropdown>
);
}

TagsInput.jsx

export default function TagsInput(props) {
    const tags = props.tags
    const setTags = props.setTags
    const [input, setInput] = React.useState('');
    const [isKeyReleased, setIsKeyReleased] = React.useState(false);

    const onChange = (e) => {
        const { value } = e.target;
        setInput(value);
    };

    const onKeyDown = (e) => {
        const { key } = e;
        const trimmedInput = input.trim();

        if ((key === ',' || key === 'Enter') && trimmedInput.length && !tags.includes(trimmedInput)) {
            e.preventDefault();
            setTags(prevState => [...prevState, trimmedInput]);
            setInput('');
        }

        if (key === "Backspace" && !input.length && tags.length && isKeyReleased) {
            e.preventDefault();
            const tagsCopy = [...tags];
            const poppedTag = tagsCopy.pop();

            setTags(tagsCopy);
            setInput(poppedTag);
            setIsKeyReleased(false);
        }

    };

    const onKeyUp = () => {
        setIsKeyReleased(true);
    }

    const deleteTag = (index) => {
        setTags(prevState => prevState.filter((tag, i) => i !== index))
    }

    return (
        <div className={classes.container}>
            {tags.map((tag, index) => <div className={classes.tag}>
                <ClearIcon className={classes.del} fontSize="big" onClick={() => deleteTag(index)} />
                {tag}
            </div>
            )}
            <input
                className={classes.input}
                value={input}
                placeholder={props.inputPlaceholder}
                onKeyDown={onKeyDown}
                onKeyUp={onKeyUp}
                onChange={onChange}
            />
        </div>);
}
1 Answers

Here you go: https://codesandbox.io/s/beautiful-albattani-kn1yfr

I added the following tags as suggestions:

const tagSuggestions = [
    "Audi",
    "Mercedes Benz",
    "Renault",
    "Ford",
    "Ferrari"
]

There isn't much to it, this is the part that renders the suggestions:

{suggestedTags.length > 0 && (
    <div className={classes.tagSuggestionWrapper}>
        {suggestedTags.map((t) => {
            return (<div key={t} className={classes.tagSuggestion} onClick={() => { selectTag(t) }}>{t}</div>);
        })}
    </div>
)}

And then there's the tag selection from suggestions:

const selectTag = (tag) => {
    setTags((prevState) => [...prevState, tag]);
    setSuggestedTags([]);
    setInput("");
}

And the search of the suggestions based on what has been typed:

const onChange = (e) => {
    const { value } = e.target;
    setInput(value);

    if(value.length < 2) return;

    const matchedSuggestions = tagSuggestions.filter((s) => {
        return s.toLowerCase().search(value.toLowerCase()) > -1;
    })
    setSuggestedTags(matchedSuggestions);
};
Related