Reputation: 5657
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
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