doctopus
doctopus

Reputation: 5657

Creating onClick event for datalist option in React

I've made a Twitch API widget which you can see here: https://twitch-react-drhectapus.herokuapp.com/

At the moment, any time you search for something, there will be a list of suggestions. I'd like to make it so that when you click on one of the datalist options it will search for that user, rather than having to click on the 'Search' button. Basically the same search function as google has.

How do I go about implementing this?

Code:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchUser, fetchSuggestions } from '../actions/index';

class SearchBar extends Component {
  constructor(props) {
    super(props);
    this.state = {
      term: ''
    };
    this.onInputChange = this.onInputChange.bind(this);
    this.onFormSubmit = this.onFormSubmit.bind(this);
  }

  onInputChange(event) {
    this.setState({
      term: event.target.value
    });
  setTimeout( this.props.fetchSuggestions(event.target.value), 300);
  }

  renderSuggestions(sug, i) {
    return (
      <option key={i} value={sug.display_name} />
    )
  }

  onFormSubmit(event) {
    event.preventDefault();
    this.props.fetchUser(this.state.term);
    this.setState({
      term: ''
    });
  }

  render() {
    const { error, suggestions } = this.props;
    return (

        <form
          className='input-group'
          onSubmit={this.onFormSubmit}>
          <input
            className='form-control'
            placeholder='Search for a Twitch user'
            value={this.state.term}
            onChange={this.onInputChange}
            list='suggestions' />
          <span className='input-group-btn'>
            <button className='btn btn-primary'>
              Search
            </button>
          </span>
          <datalist id='suggestions'>
            {suggestions.map(this.renderSuggestions)}
          </datalist>
        </form>


        // {/* {error && <div className='alert alert-danger'>{error}</div>} */}


    )
  }
}

function mapStateToProps({ error, suggestions }) {
  return { error, suggestions };
}

export default connect(mapStateToProps, { fetchUser, fetchSuggestions })(SearchBar);

Upvotes: 3

Views: 2462

Answers (1)

Raphael
Raphael

Reputation: 562

My solution is to test event.nativeEvent.inputType against the list of possible values to determine how the user entered the value. For my use case, I only need to differentiate between "typed" and "anything else" so my solution may not be completely exhaustive.

Input type is undefined for an option click.

const userDidntTypeIt = (inputType) => {
  return [
    undefined,
    'insertFromYank',
    'insertFromDrop',
    'insertFromPasteAsQuotation',
    'insertTranspose',
    'insertCompositionText',
    'insertLink',
  ].includes(inputType);
};

const handleOnChange = (e, onOptionClick, onValueType) => {
    const { inputType } = e.nativeEvent;
    const { value: targetValue } = e.target;
    if (userDidntTypeIt(inputType)) onOptionClick?.(targetValue);
    else onValueType?.(targetValue);
  };

And then your data list should look something like this:

const onOptionClick = (option) => console.log('clicked', option);
const onValueType = (value) => console.log('typed', value);

const onChange = (e) => handleOnChange(e, onOptionClick, onValueType);

return (
  <input
    type="text"
    list="data"
    value={value}
    onChange={onChange}
  />
  <datalist>
    {options.map((item) => <option key={item}>{item}</option>)}
  </datalist>
);

Upvotes: 0

Related Questions