user10276993
user10276993

Reputation:

Adding a class to a certain element in ReactJS

I'm new working with ReactJS, I started a project a simple CRUD just for practice. So, I have a table and I want to add a class so that this element disappears when I press a button

The problem is when I press the button delete, React adds a class to all elements, disappearing all of them

How to delete only the parent element of a clicked button ? I tried to get the id of an event but I don't know how to specify to what element I want to add a class.

deleteTask(e, id){
  //let trDelete = 
  e.currentTarget.parentNode.getAttribute('key');
  M.toast({html: 'Task Deleted'})
  const currState = this.state.active;
  this.setState({active: !currState});

    }
{
this.state.tasks.map(task => {
    return (
        <tr data-key={task._id} key={task._id}  className={this.state.active ? "scale-transition scale-out": ""}>
            <td>{task.title}</td> 
            <td>{task.description}</td>
            <td>
                <button className="btn light-blue darken-4" onClick={(e) => this.deleteTask(e, task._id)}>
                    <i className="material-icons">
                        delete
                    </i>
                </button>
                <button className="btn light-blue darken-4" style={{margin: '4px'}}>
                <i className="material-icons">
                        edit
                    </i>
                </button>
            </td>
        </tr>
    )
  })
 }

Upvotes: 2

Views: 352

Answers (2)

Dacre Denny
Dacre Denny

Reputation: 30360

To apply CSS classes on a per-item basis, you will need to track the class(es) of each item by adding extra component state.

A simple solution here would be to update your deleteTask() function:

deleteTask = (event, taskId) => { 

    this.setState(state => {

        /* 
        Iterate each task in state, and add isDeleted to task(s) with matching id 
        */
        return { 
            tasks : state.tasks.map(task => 
            (taskId === task._id ? { ...task, isDeleted : true } : { ...task }))
        };

    }, () => {

        /*
        Show toast popup after stat change
        */
        M.toast({html: 'Task Deleted'});
    });
}

And then update your table rendering to account for the new isDeleted item state:

<tr data-key={task._id} key={task._id}  
    className={ task.isDeleted ? "scale-transition scale-out": ""}>
    { /* Existing table markup */ }
</tr>

Upvotes: 2

Ezra
Ezra

Reputation: 1168

The class is being added to all of them, because you're iterating over each item and assigning the class to each task item based on active being constant.

If you want to delete or hide a task, the setState should be affecting this.state.tasks and not this.state.active.

I'm guessing your update and state is intended to look more like this:

deleteTask(e, id) {

  // Return new task objects to prevent mutation of state
  const tasks = this.state.tasks.map(task => {
    return task.id === id ? {...task, active: !task.active} : {...task};
  });

  // Executes callback after state update is complete
  this.setState({tasks}, () => M.toast({html: 'Task Deleted'}));
}

Disclaimer: I don't know what you're using to transpile, so you might have to use the equivalent of the object spread and property shorthand.

Upvotes: 0

Related Questions