user7453521
user7453521

Reputation:

Filtering an array in React

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

Answers (2)

user7896145
user7896145

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

Hamms
Hamms

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

Related Questions