[SalesForce] Applying background color to the tag for the selected row in LWC

I am displaying the records from the custom object using the HTML table in LWC.
I am using this below tag to iterate over the list of records.
I want that on click of a row the background color of the gets change and when I click another row then the background color of that row gets changed.

<tbody>
  <template for:each={testList} for:item="test" for:index="idx">
   <tr class={test.rowSelected} key={test.Id} data-id={test.Id} onclick={handleClick}>
    <td>
     {test.name}
    </td>
   </tr>
  </template>
 </tbody>

JS

import getTestList from '@salesforce/apex/TestClass.getTestList';
@track testList
@track rowSelected;
@wire(getTestList)
wiredlist({data, error}) {
  if(data) {
    this.testList = data;
    this.error = undefined;
  } else {
    this.error = error;
    this.testList = undefined;
  }
}

handleClick(event){

  this.testList.forEach(row =>{
    if(row.Id === event.currentTarget.dataset.id){
        row.rowSelected = 'row-color'
    } else {
        row.rowSelected = '';
    }
  });
 }

CSS

.row-color {
 backgorund: blue;
}

When I click on any row, all row's background-color gets changed and not just the one which I clicked.

Can anyone help on how to apply the style on the current item in the html table?

Best Answer

You can't do this with a single rowSelected class-level attribute. You need one for each of the rows. And the onclick handler will setup that value when the row is clicked, also you need to reset the old one.

See the sample code.

@track testList = [{ Id: '1' }, { Id: '2' }, { Id: '3' }, { Id: '4' }, { Id: '6' }, { Id: '5' }];

handleClick(event) {
    this.testList.forEach(row =>{
        if(row.Id === event.currentTarget.dataset.id){
            row.rowSelected = 'row-color'
        } else {
            row.rowSelected = '';
        }
    });
}

Now on the HTML side, you just to assign that attribute the class using the item variable of the iterator.

<tbody>
    <template for:each={testList} for:item="test" for:index="idx">
        <tr class={test.rowSelected} key={test.Id} data-id={test.Id} onclick={handleClick}>
            <td style="height: 10px; width: 100px; border: 1px solid grey;">
                {test.Id}
            </td>
        </tr>
    </template>
</tbody>

Note that the inline styles are not recommended here, I used them just for the demo purposes.

Also, your CSS should be something like.

.row-color{
    background:lightcyan; // or whatever color you prefer.
}

You can also use the method suggested by @Phil W, tr[data-selected="true"] just that you will set the data attribute instead of the class with some modification.

Update Based on the update in question.
You need to deep clone the data returned by the wired method like below. Using JSON.parse(JSON.stringify())

@wire(getTestList)
wiredlist({data, error}) {
  if(data) {
    this.testList = JSON.parse(JSON.stringify(data));
    this.error = undefined;
  } else {
    this.error = error;
    this.testList = undefined;
  }
}
Related Topic