1

I am adding table rows to a table dynamically. Here how it looks in the UI:

Sample screenshot

Here is the logic I am using to create a new row:

I have a state variable this.state = ({rows: []})

on the "Insert" button click I am doing:

addNewRow = () => {
        this.setState({rows: this.state.rows.concat([{}])});
    }

In my render() I have the below code:

const rows = this.state.rows.map((item, id) => {
            return(
                <tr key={id}>
                    <td>Something</td>
                    <td>Something</td>
                    <td>Something</td>
                    <td>Something</td>
                    <td><Button onClick={(event) => this.removeRow(event, id)}>Delete</Button></td>
                </tr>
            );
        });

and, obviously my final table code looks like the below:

<Table borderless>
    <tbody>
       {rows}
    </tbody>
<tfoot>
    <tr>
       <td>
        <Button onClick={() => {this.addNewRow()}} size="sm" className="float-left">insert</Button>
       </td>
    </tr>
</tfoot>
</Table>

Here is my removeRow function:

removeRow = (event, id) => {
        event.preventDefault();
        var index = this.state.rows.indexOf(id);
        this.state.rows.splice(index, 1);
        this.setState({rows: this.state.rows});
    }

The entire code works. I have changed variable names and stripped unwanted codes from them, but this is to give an idea of how I designed it.

My problem is when I click on "Delete" button, it always removes the last item in the row, not the item row which I have clicked. How to fix this?

I googled about the same, and I found few examples, to be honest, I felt they are complex and so I decided to go on my own way.

Please advise what need to be done to fix this issue.

1
  • did you try my edited answer ? Commented Jun 29, 2018 at 9:12

3 Answers 3

1

That's because you're using an array index as a key for <tr> element.

React uses the key to identity what to insert, or delete from existing DOM tree.

Please use any other unique identifier, for instance, Date.now() as a key, and save this key as a part of rows state.

addNewRow = () => {
  const { rows } = this.state
  this.setState({
    rows: [
      ...rows,
      {
        id: Date.now(),
      },
    ],
  })
}

render() {
   const rows = this.state.rows.map((item, index) => (
     <tr key={item.id}>
     </tr>
   ))
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. Can you show me a sample setting Date.now() saving it to the part of rows. I am confused where it should be done and what will be the changes having to my removeRow function.
1

Never Mutate the state directly in React:

You need to do it this way:

removeRow=(event,id)=>{  
  var array = [...this.state.rows]; // make a new copy of array instead of mutating the same array directly. 
  var index = array.findIndex(x => x.id===id); //find the index of item which matches the id passed to the function
  array.splice(index, 1);
  this.setState({people: array});
  }

4 Comments

Thanks noted. But this still doesn't fix my issue. It still delete's the last row instead of current clicked row.
i have edited my answer. the problem might be in finding the Index of item. see i have changed the logic for finding the index
Yes, I did. Good catch on finding that indexOf is causing the first issue. You are right. That line in my code always returns -1. Your code of using findIndex is perfect. It finds the index fine, but still at the end react removes the last added element :(
can you add your minimal code to sandbox it will be very easy to find the actual problem.
0

That is because you are using .map() wrong.

You'll need to pass item like this:

<td><Button onClick={(event) => this.removeRow(event, item)}>Delete</Button></td>

You were passing index of the array as id. Because, second parameter of array.map operator is the index of that element in the array.

Do this instead:

removeRow = (event,item) => {  
  var array = [...this.state.rows]; // make a new copy of array instead of mutating the same array directly. 
  var index = array.indexOf(item)
  array.splice(index, 1);
  this.setState({people: array});
  }

4 Comments

what are you doing with item in removeRow and where are getting the id from ?
Item is being passed. Of which OP wants to finds the index of.
Makes sense. But still it removes the last item, instead of the clicked item.
Where did you logged it?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.