[Help!] Delete from a list

Hi all,

I’m returning to a project and I need to delete an item from a list, but for some reason I can’t get my head around it. Here’s the code:

import React from 'react';

DashCategoryList = React.createClass({
  deleteCat: function(event) {
    event.preventDefault();

    Meteor.call('deleteCategory', this._id);
    Bert.alert({title: "Category Deleted", type: 'success', icon: 'fa-check', style: 'growl-top-right'});
  },

  renderItems( item ) {
    return <li key={ item._id } item={ item } className="list-group-item text-left">
      { item.title }<a className="deleteCat" href="" onClick={ this.deleteCat }><i className="fa fa-times"></i></a>
    </li>;
  },

  render() {
    return (
      <ul className="list-group categories">
        {this.props.category.map( ( item ) => {
          return this.renderItems( item );
        })}
      </ul>
    );
  }
});

The list is displaying fine. In fact everything is displaying fine. When I click delete, the popup is telling me it’s deleted the category but it isn’t removed from the collection. Here is the method to remove it:

Meteor.methods ({
  deleteCategory: function(catId) {
    Categories.remove(catId);
  }
});

It’s probably something really silly I’m missing. But any help would be greatly appreciated :blush:

Thanks.

Here’s your issue:

onClick={this.deleteCat}

And then in deleteCat you reference this._id which is undefined. You need to set the this context by using bind:

onClick={this.deleteCat.bind(item)}

Or you could just pass the ID in:

 onClick={_ => this.deleteCat(item._id)}

i think the issue is due to it didn’t re-render after deletion. There are two ways that I can think of, one is using the this.setState in your deleteCat method, and the second is utilize the shouldComponetUpdate . However, the above two ways might result a race condition that you might not see the Bert.alert due to the re-rendering. the way you can solve it is by passing your item data to a child component. I hope this help

Hi @ffxsam,

Thanks for your response! Doesn’t quite work though, getting this in console:

Warning: bind(): React component methods may only be bound to the component instance. See DashCategoryList

The second method then tells me that event.preventDefault() isn’t a function. Removing it then returns back to normal (bert alert fires, but category isn’t removed).

Go for this solution then:

DashCategoryList = React.createClass({
  deleteCat: function(event, itemId) {
    event.preventDefault();

    Meteor.call('deleteCategory', itemId, (error, result) => {
      if (!error) {
        Bert.alert({title: "Category Deleted", type: 'success', icon: 'fa-check', style: 'growl-top-right'});\
      }
    });
  },

  renderItems( item ) {
    return <li key={ item._id } item={ item } className="list-group-item text-left">
      { item.title }<a className="deleteCat" href="" onClick={ e => this.deleteCat(e, item._id) }><i className="fa fa-times"></i></a>
    </li>;
  },

  render() {
    return (
      <ul className="list-group categories">
        {this.props.category.map( ( item ) => {
          return this.renderItems( item );
        })}
      </ul>
    );
  }
});
1 Like

You sir, are a gentleman and a scholar!

Mind explaining your solution a bit? I think I know what’s going on there, but a bit of clarity would be awesome.

Thanks again!

Sure! So the main changes I made were this:

onClick={ e => this.deleteCat(e, item._id) }

What’s going on here is, I’m just making a new function on the fly, taking the event object (e) and passing it to deleteCat, along with the item ID. And then we’ve got: (see comments)

  // deleteCat now accepts two arguments
  deleteCat: function(event, itemId) {
    event.preventDefault();

    // Remember that Meteor.call accepts a callback as the last parameter. I moved the Bert.alert
    // call inside the callback, so that it only gets called once the method is actually completed.
    Meteor.call('deleteCategory', itemId, (error, result) => {
      if (!error) {
        Bert.alert({title: "Category Deleted", type: 'success', icon: 'fa-check', style: 'growl-top-right'});\
      }
    });
  },