Reputation:
I am making a To-Do Application in React. I got stuck at some point.
I'm mapping through items in an array, and displaying it in an unordered list. I'm trying to use the filter function, to remove the deleted items from the array.
I assume that the problem in my code can be somewhere there, that I am passing the event object but pointing to the button, instead of the list item.
How can I do it in React? You can find my code attached below.
Also it would be great to clear the input field after submitting an item.
import React, { Component } from 'react';
class ToDoList extends Component {
constructor(props) {
super(props);
this.state = {list: [], items: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleRemove = this.handleRemove.bind(this);
}
handleChange(event) {
this.setState({items: event.target.value})
console.log(event.target.value);
}
handleSubmit(event) {
this.setState({ list: [...this.state.list, this.state.items]})
event.preventDefault();
}
handleRemove(event) {
const filteredArray = this.state.list.filter(item => item !== event.target.value)
this.setState({list: filteredArray});
console.log(event.target);
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<label>
<input
type="text"
value={this.state.value}
onChange={this.handleChange} />
</label>
<input
onClick={this.handleSubmit}
type="submit"
value="Submit" />
</form>
<ul>
{this.state.list.map((i, index) => (
<li key={index+1}>
{i}
<button
onClick={this.handleRemove}>
X
</button>
</li>
))}
</ul>
<p>Remaining: {this.state.list.length}</p>
</div>
);
}
}
export default ToDoList;
Upvotes: 1
Views: 9904
Reputation:
Check at this line:
<li key={index+1}>{i}<button onClick={this.handleRemove}>X</button></li>
Inside handleRemove
, the instruction event.target
point to the button. A button doesn't have a value
attribute. So, you need to go up to parent and get it's content:
// childNodes[0] is a TextNode, so, to get it's content use data pop
const toRemove = event.target.parentNode.childNodes[0].data.trim();
const filteredArray = this.state.list.filter(item => item !== toRemove);
Another option is wrap the item in a element, like span
:
<li key={index+1}><span>{i}</span><button onClick={this.handleRemove}>X</button></li>
And on remove get it to get the item value:
const toRemove = event.target.parentNode.children[0].textContent.trim();
const filteredArray = this.state.list.filter(item => item !==
event.target.value)
Upvotes: 0
Reputation: 5107
I would recommend using the optional additional arguments to .bind
in order to change what's passed to your handler.
Call .bind(this. index)
within your map method to pass the index of the element to be removed to the handler:
<ul>
{this.state.list.map((i, index) => (
<li key={index+1}>{i}<button onClick={this.handleRemove.bind(this, index)}>X</button></li>
))}
</ul>
And then update the handler to just remove the specified element:
handleRemove(index) {
const filteredArray = this.state.list.filter((_, i) => i !== index);
this.setState({
list: filteredArray
});
}
As to your second question, you should first fix up your input so its value is actually controlled by the state by changing value={this.state.value}
to value={this.state.items}
:
<input type="text" value={this.state.items} onChange={this.handleChange} />
And then simply clear this.state.items
upon submission:
handleSubmit(event) {
this.setState({
list: [...this.state.list, this.state.items],
items: ''
})
event.preventDefault();
}
Upvotes: 1