1

I am referring to this tutorial for simple react autocomplete https://www.digitalocean.com/community/tutorials/react-react-autocomplete

But I have a slightly different requirement. Instead of typing something on the input field, I want all the suggestions to come up on clicking the input field. I am basically implementing a requirement where on clicking the input field, it should show user what are the available options.

Here is my sandbox https://codesandbox.io/s/distracted-easley-wdm5x

Specifically in the Autocomplete.jsx file (as mentioned below)

import React, { Component, Fragment } from "react";
import PropTypes from "prop-types";

class Autocomplete extends Component {
  static propTypes = {
    suggestions: PropTypes.instanceOf(Array)
  };

  static defaultProps = {
    suggestions: []
  };

  constructor(props) {
    super(props);

    this.state = {
      // The active selection's index
      activeSuggestion: 0,
      // The suggestions that match the user's input
      filteredSuggestions: [],
      // Whether or not the suggestion list is shown
      showSuggestions: false,
      // What the user has entered
      userInput: ""
    };
  }

  onChange = (e) => {
    const { suggestions } = this.props;
    const userInput = e.currentTarget.value;

    // Filter our suggestions that don't contain the user's input
    const filteredSuggestions = suggestions.filter(
      (suggestion) =>
        suggestion.toLowerCase().indexOf(userInput.toLowerCase()) > -1
    );

    this.setState({
      activeSuggestion: 0,
      filteredSuggestions,
      showSuggestions: true,
      userInput: e.currentTarget.value
    });
  };

  onClick = (e) => {
    this.setState({
      activeSuggestion: 0,
      filteredSuggestions: [],
      showSuggestions: false,
      userInput: e.currentTarget.innerText
    });
  };

  onClick2 = (e) => {
    console.log("text check", e.currentTarget.innerText);
    if (e.currentTarget.innerText === "") {
      const { suggestions } = this.props;
      const filteredSuggestions = suggestions;
      this.setState({
        activeSuggestion: 0,
        filteredSuggestions,
        showSuggestions: true,
        userInput: e.currentTarget.innerText
      });
    }
  };

  onKeyDown = (e) => {
    const { activeSuggestion, filteredSuggestions } = this.state;

    // User pressed the enter key
    if (e.keyCode === 13) {
      this.setState({
        activeSuggestion: 0,
        showSuggestions: false,
        userInput: filteredSuggestions[activeSuggestion]
      });
    }
    // User pressed the up arrow
    else if (e.keyCode === 38) {
      if (activeSuggestion === 0) {
        return;
      }

      this.setState({ activeSuggestion: activeSuggestion - 1 });
    }
    // User pressed the down arrow
    else if (e.keyCode === 40) {
      if (activeSuggestion - 1 === filteredSuggestions.length) {
        return;
      }

      this.setState({ activeSuggestion: activeSuggestion + 1 });
    }
  };

  render() {
    const {
      onChange,
      onClick2,
      onClick,
      onKeyDown,
      state: {
        activeSuggestion,
        filteredSuggestions,
        showSuggestions,
        userInput
      }
    } = this;

    let suggestionsListComponent;

    if (showSuggestions) {
      if (filteredSuggestions.length) {
        suggestionsListComponent = (
          <ul className="suggestions">
            {filteredSuggestions.map((suggestion, index) => {
              let className;

              // Flag the active suggestion with a class
              if (index === activeSuggestion) {
                className = "suggestion-active";
              }

              return (
                <li className={className} key={suggestion} onClick={onClick}>
                  {suggestion}
                </li>
              );
            })}
          </ul>
        );
      } else {
        suggestionsListComponent = (
          <div className="no-suggestions">
            <em>No suggestions, you're on your own!</em>
          </div>
        );
      }
    }

    return (
      <Fragment>
        <input
          type="text"
          onChange={onChange}
          onKeyDown={onKeyDown}
          value={userInput}
          onClick={onClick2}
        />
        {suggestionsListComponent}
      </Fragment>
    );
  }
}

export default Autocomplete;

In the input element in return section,

<input
          type="text"
          onChange={onChange}
          onKeyDown={onKeyDown}
          value={userInput}
          onClick={onClick2}
/>

I have added a onClick functionality that calls the function onClick2.

onClick2 = (e) => {
    console.log("text check", e.currentTarget.innerText);
    if (e.currentTarget.innerText === "") {
      const { suggestions } = this.props;
      const filteredSuggestions = suggestions;
      this.setState({
        activeSuggestion: 0,
        filteredSuggestions,
        showSuggestions: true,
        userInput: e.currentTarget.innerText
      });
    }
  };

My function simply returns all the suggestions back on clicking the input field. I am able to select items from suggestions and it gets put in the input field. But when I click on the input field again, the value disappears.

I want this autocomplete suggestion to only show once on clicking the empty input field and after selecting the item from list, I should be able to edit the value further.

What am I doing wrong?

2 Answers 2

1

Input values are not stored into innerText, but in value prop.

Look at this:

onClick2 = (e) => {
    console.log("text check", e.currentTarget.innerText);
    if (e.currentTarget.value === "") {
      const { suggestions } = this.props;
      const filteredSuggestions = suggestions;
      this.setState({
        activeSuggestion: 0,
        filteredSuggestions,
        showSuggestions: true,
        userInput: e.currentTarget.value
      });
    }
  };

This should solve your problem

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

Comments

1

You are doing the wrong check in onClick2 function. Instead of checking e.currentTarget.innerText === "", it has to be e.target.value as we are validating the text in input field.

onClick2 = (e) => {
    console.log("text check", e.target.value);
    if (e.target.value === "") {
      const { suggestions } = this.props;
      const filteredSuggestions = suggestions;
      this.setState({
        activeSuggestion: 0,
        filteredSuggestions,
        showSuggestions: true,
        userInput: e.currentTarget.innerText
      });
    }
  };

Here is the working link - https://codesandbox.io/s/jolly-meadow-5fr6x?file=/src/Autocomplete.jsx:1344-1711

Comments

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.