1

I am displaying the records from the custom object test__c using the HTML table in LWC. I am using this below tag to iterate over the list of records.

<tbody>
<template for:each={testList} for:item="test">
<tr key={test.Id}>
<td>
{data}
</td>

I want to access the current item (for:item="test") in js file.

Like, in js, I am giving

@track record = {};
@track field;

I want (for:item="test") record data to populate in the @track record property.

Can anyone help me with this?

5
  • Hi SGDC IN, welcome to SFSE! Why there is a need to create a custom table instead of using lightning-datatable? Jul 1, 2020 at 17:29
  • Hi Rahul, yes we need a customized table that's why we are using HTML instead of lightning-datatable ?
    – SFDC IN
    Jul 1, 2020 at 17:34
  • ok, you can use the data attributes and index to get the current records. Jul 1, 2020 at 17:44
  • can you help me with the syntax in context to my code ?
    – SFDC IN
    Jul 1, 2020 at 18:03
  • @SGDCIN What do you mean access the current record from the table? Are you talking to access it on click or how?
    – Arthlete
    Jul 1, 2020 at 22:13

1 Answer 1

1

I am not completely sure what it is that you mean when you say "current record" but I imagine that it's related to some sort of event like onclick, onkeyup, etc.

As @rahulgawale mentioned you can leverage the use of HTML's data attributes. From the documentation:

data-* attributes allow us to store extra information on standard, semantic HTML elements without other hacks such as non-standard attributes, extra properties on DOM...

This is how you can add data attributes using the code you have provided:

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

Next in the JS you will have to add a method to handle the click event:

handleClick(evt) {
    // This will give you the id value that we just stored as a data attribute in the table cell.
    const recordId = evt.target.dataset.id;
    // Next you can iterate over your list and find which record the user interacted with.
    for (let aRecord of this.testList) {
        if (recordId === aRecord.Id) {
            this.record = aRecord;
            this.field = aRecord.Field__c;
        }
    }
}

Iterating over the list of records testList and comparing each record's Id to recordId is not very efficient.

You can improve the above code if you build an additional object-type variable when you first retrieve the testList from Salesforce:

testListObj = {};

@wire(getTestList, { recordId: $recordId})
wireTestList({error, data}) {
    if (data) {
        this.testList = data;
        // Populate the new object mapping every record to its id.
        for (let testRecord of this.testList) {
            this.testListObj[testRecord.Id] = testRecord;
        }
    } else if (error) {
        // handle your error
    }
}

At this point you can quickly find the record you are looking for when the user interacts with any table cell like so:

handleClick(evt) {
    // This will give you the id value that we just stored as a data attribute in the table cell.
    const recordId = evt.target.dataset.id;
    // At this point you no longer need to iterate and compare each record's id because you have an object that holds all records so you can directly reference the correct record below.
    this.record = this.testListObj[recordId];
    this.field = this.testListObj[recordId].Field__c;
}

EDIT As per request by OP I am expanding my answer to include an onblur event on a textarea inside the <td></td>.

If you want to use a placeholder you can go with this:

<tbody>
    <template for:each={testList} for:item="test">
        <tr key={test.Id}>
            <td data-id={test.Id}>
                <textarea data-id={test.Id} onblur={handleOnBlur} placeholder={test.Field__c}></textarea>
            </td>
        </tr>
    </template>
</tbody>

JS:

handleOnBlur(evt) {
    // This will give you the id value that we just stored as a data attribute in the table cell.
    const recordId = evt.target.dataset.id;
    const placeholderValue = evt.target.getAttribute('placeholder');
    // Retrieve the value out of the textarea.
    const textAreaValue = evt.target.value;
    // Compare the value from the textarea to the original value for the record in SF.
    if (placeholderValue  !== textAreaValue) {
        this.record = this.testListObj[recordId];
        this.field = this.testListObj[recordId].Field__c;
    }
}

Additionally if you don't want to use a placeholder but want to prepopulate the field value in the textarea instead you can do this:

<tbody>
    <template for:each={testList} for:item="test">
        <tr key={test.Id}>
            <td data-id={test.Id}>
                <textarea data-id={test.Id} onblur={handleOnBlur}
                    {test.Field__c}
                </textarea>
            </td>
        </tr>
    </template>
</tbody>

Now in the JS you can compare the textarea value to the value from the testListObj:

handleOnBlur(evt) {
    // This will give you the id value that we just stored as a data attribute in the table cell.
    const recordId = evt.target.dataset.id;
    // Retrieve the value out of the textarea.
    const textAreaValue = evt.target.value;
    // Compare the value from the textarea to the original value for the record in SF.
    if (this.testListObj[recordId].Field__c !== textAreaValue) {
        this.record = this.testListObj[recordId];
        this.field = this.testListObj[recordId].Field__c;
    }
}
9
  • 1
    +1 . Though you could have used testListobj instead of testList in HTML, The idea of mapping records with is nice!! @Arthlete Jul 2, 2020 at 2:54
  • @Arthlete Thanks for responding. My actual scenario is that I have one editable field that is the text area with id to identify that the user clicked on it. I am using the onblur event. So, what I need is to access the current value of that field so that the field get updated only when it is not equal to the current value.
    – SFDC IN
    Jul 2, 2020 at 4:56
  • @rahulgawale Thank you! However I cannot use testListObj in the HTML. Per documentation: To render a list of items, use for:each directive or the iterator directive to iterate over an array. testListObj is an object and not an array. If there's a different way to use it in the HTML please don't hesitate to show me!
    – Arthlete
    Jul 2, 2020 at 7:04
  • @SGDCIN I will update my answer, give me a little bit of time.
    – Arthlete
    Jul 2, 2020 at 7:04
  • @Arthlete Ohh yes, its object. But the other way is using index of an array and for:index="index". With this you can directly refer array element like array[index]`. Jul 2, 2020 at 7:35

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.