I'm using react-bootstrap-typeahead
component to predict user input into text box, but I am having trouble setting the state so user can click on a selection in the dropdown menu.here
So far code I have is here. The function handleAddtask
adds task to tasklist when typed in, but I cannot get it to assign to typeahead dropdown. (I am still learning react so any resources on this would also be appreciated).
import React, { Component } from "react";
import PropTypes from "prop-types";
import { Typeahead } from "react-bootstrap-typeahead";
class AddWatchlistForm extends Component {
constructor(props) {
super(props);
this.state = {
taskName: ""
};
this.handleAddTask = this.handleAddTask.bind(this);
}
static propTypes = {
newTask: PropTypes.func.isRequired
};
render() {
return (
<div className="row">
<div className="col-md-6 col-md-offset-3">
<div style={{ margin: "20px" }}>
<div className="row">
<div className="col-md-6">
<Typeahead
placeholder=""
onChange={e => this.updateTaskName(e)}
onClick={(e => this.updateTask(e), this.handleAddTask)}
value={this.state.taskName}
onKeyPress={e => this.checkEnterKey(e)}
labelKey={option =>
`${option.ticker} ${option.security_type}`
}
options={[
{
"": 0,
ticker: "A",
security_type: "Stock"
},
{
"": 1,
ticker: "AA",
security_type: "Stock"
},
{
"": 2,
ticker: "AAA",
security_type: "Stock"
},
{
"": 3,
ticker: "AAAU",
security_type: "Stock"
},
{
"": 4,
ticker: "AACG",
security_type: "Stock"
}
]}
/>
</div>
<div className="col-md-4">
<button
type="button"
className="btn btn-primary"
onClick={this.handleAddTask}
>
{" "}
Add New...{" "}
</button>
</div>
</div>
</div>
</div>
</div>
);
}
checkEnterKey(e) {
var keyCode = e.which || e.keyCode;
if (keyCode == 13) {
if (this.state.taskName.trim() !== "") {
this.props.newTask(this.state.taskName);
}
}
}
updateTaskName(e) {
this.setState({ taskName: e.target.value });
}
updateTask(e) {
this.setState({ taskName: e.target.options.ticker });
console.log(this.state);
}
handleAddTask(e) {
let name = e.target.value;
if (this.state.taskName.trim() !== "")
this.props.newTask(this.state.taskName);
}
}
export default AddWatchlistForm;
Suggestion, a better way of doing things using Arrow Functions preserving the context of this
:
Remove the following...
constructor(props) {
super(props);
this.state = {
taskName: ""
};
this.handleAddTask = this.handleAddTask.bind(this);
}
handleAddTask(e) {
let name = e.target.value;
if (this.state.taskName.trim() !== "")
this.props.newTask(this.state.taskName);
}
And add this instead:
state = {
taskName: ""
};
handleAddTask = e => {
let name = e.target.value;
if (this.state.taskName.trim() !== "")
this.props.newTask(this.state.taskName);
}
And the reason why you get the TypeError
due to undefined
is the same reason. I just tried by replacing all the normal functions to arrow functions and they all worked fine now. Else you should be binding to this
for every single class property function, which is a tedious double process and performance intensive.
Also, in the handleAddTask
function, please update:
handleAddTask = e => {
let name = e.target.value;
if (this.state.taskName.trim() !== "")
this.props.newTask(name);
};
Solution
The problem is with the e
that gets passed to. Change your updateTaskName
function to:
updateTaskName = e => {
this.setState({ taskName: e.length > 0 ? e[0].security_type : "" });
};
This is because, e
is:
e = {
"": 2,
ticker: "AAA",
security_type: "Stock"
};
Working Demo: https://codesandbox.io/s/confident-moore-wsq5p