1

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?

  • Where's your JavaScript? – sfdcfox Sep 22 at 16:34
  • You have a typo, you used both Id and id. Presumably, it should be one or the other. – sfdcfox Sep 22 at 16:36
  • 2
    Have you thought about using CSS like "tr[data-selected="true"] { background-color: blue }" and adding the "data-selected" attribute to the selected tr? This would set the background on that row. – Phil W Sep 22 at 16:42
  • My apologies for the limited information, I have updated the code which I have written till now. – SFDC IN Sep 22 at 16:44
  • The fundamental issue you have is that all the generated rows receive the rowSelected value in their class attribute. You need to ensure that only the selected row gets this value set. The easiest way to do that is to ensure that your interated objects ("test") have a property that is set into the class attribute and only set it to "row-color" for the actual selected "test" instance. – Phil W Sep 22 at 16:58
1

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;
  }
}
| improve this answer | |
  • I tried your way, but giving error as object is not extensible – SFDC IN Sep 22 at 18:24
  • 1
    You have to clone the data you get back from the server or you need to use an object that wraps each item back from the server and adds the per-row flag. – Phil W Sep 22 at 18:52
  • Tried but unable to do that. I created a field (kept it as empty) in the object also but that doesn't seem to get fetched. – SFDC IN Sep 23 at 7:30
  • @SFDCIN can you update your code in question? – rahul gawale Sep 23 at 7:46
  • Hi, I have updated the code but this code is giving me error as the object is not extensible. I tried to copy the testList in another object but again it was giving the error – SFDC IN Sep 24 at 6:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.