justDan
justDan

Reputation: 2333

ReactJS: Remove item from list without ID?

I have an issue I can't seem to crack even after checking out a few other posts on here and trying a few things out. I am playing around with React and making a quick todo list. Easy enough as I can add new names and display them on the page as intended. I want to be able to delete items that I choose and for that I was looking around and saw others doing something like this to delete items:

deleteName(id, e) {
    const { names } = this.state;

    this.setState({
        names: names.filter(name => name.id !== id)
    });
}

That made sense to me but I wasn't adding any id's to my <li> items so I thought I could just do:

this.setState({
   names: names.filter(name => name !== name)
});

But this will just delete the whole list. What am I doing wrong? Should I restructure how I add names to the array to have an id and check that? I'll post the full component code below. Any help I can get is always appreciated. Thanks guys.

class ContactListPage extends React.Component {
    constructor(props, context) {
      super(props, context);

      this.state = {
        names: []
      };

      this.addName = this.addName.bind(this);
      this.deleteName = this.deleteName.bind(this);
    }

  addName(name) {
    const { names } = this.state;

    if (name === '') {
        console.log('add a name first!')
    } else {
        this.setState({
          names: names.concat(name)
        });
    }
  }

  deleteName(id, e) {
    const { names } = this.state;

    this.setState({
        names: names.filter(name => name !== name)
    });
  }

  render() {
    const { names } = this.state;

    const named = names.map((name, i) => (
        <Card key={i} className='todo-list'>
            <CardText>
              <li>{name}    
                <FloatingActionButton className='fab-delete' mini onClick={this.deleteName}>
                           <i className="material-icons fab-icon-delete" style={{color: 'white'}}>-</i>
                        </FloatingActionButton>
              </li>
            </CardText>
        </Card>
    ));

    return (
        <div className='contact-list'>
          <div className="field-line">
            <NewName addName={this.addName} />
            <ul className='new-name'>
              {named}
            </ul>
          </div>
        </div>
    );
  }
}

Upvotes: 2

Views: 2381

Answers (3)

fubar
fubar

Reputation: 17398

It's hard to tell, but are you referencing name when the passed argument to your callback is actually called id?

Try this:

deleteName(name) {
    this.setState((prevState) => ({
        names: prevState.names.filter(_name => name !== _name);
    }));
}

And change the following:

onClick={this.deleteName.bind(null, name)}

Upvotes: 2

Douglas Parker
Douglas Parker

Reputation: 1214

You're comparing each name with itself, that will yield an empty list regardless of what's in it (except I guess NaN?).

names.filter(name => name !== name)

I think you want to pass the name into your delete function from the view. It's been a while since I've done React, but you could probably do this with a lambda in the JSX.

deleteName(nameToDelete) {
    const { names } = this.state;

    this.setState({
        names: names.filter(name => name !== nameToDelete)
    });
}

render() {
    // Simplified to focus on the onClick change
    return names.map(name => <Card>
        ...
        <FloatingActionButton onClick={(e) => this.deleteName(name)} ... />
        ...
    </Card>);
}

If you need to worry about duplicate names, then you can pass the current index into deleteName() rather than the string itself. Up to you if that's necessary or not.

Upvotes: 3

Stephen L
Stephen L

Reputation: 2339

In the callback for the filter, name !== name will always be false since an object is identical to itself. i.e name === name. Therefore the expression names.filter(name => name !== name) will return an empty array and erase your results. You can change your onClick handler to something like this to pass in your id: onClick={(e) => this.deleteName(i, e)} and then use names.filter((name, i) => i !== id) to 'delete' the name, although I imagine you would would probably want to make a copy of the names array and then splice the corresponding name out of it.

Upvotes: 0

Related Questions