4

I have table that shows list of record, I want to make call to javascript function with each iterated value as a parameter.
Here is the detail of my js and html file:

OnboardingPage.js


import getBacklog from '@salesforce/apex/OnboardingHandler.getOnboardingBacklog';

export default class OnboardingPage extends LightningElement {
    @wire(getBacklog) onboardingList;

    doSomething(onboardingId) {
        console.log('clicked: ' + onboardingId);
    }
}

OnboardingPage.html

<template>
    <lightning-card title="Onboarding" icon-name="action:new_task">
        <div class="slds-m-around_medium">
            <template if:true={onboardingList.data}>
                <table id="tblOnboardingList">
                    <thead>
                        <tr>
                            <th>Name</th>
                            <th>Email</th>
                            <th>Phone</th>
                        </tr>
                    </thead>
                    <tbody>
                        <template for:each={onboardingList.data} for:item="dt" for:index="indexvar">
                            <tr id="datarow">
                                <td>
                                    <!-- need to call js function with the parameter 
                                    <a onClick={doSomething(dt.Id)}>
                                        {!dt.Account.Name}
                                    </a>
                                </td>
                                <td>{!dt.Email}</td>
                                <td>{!dt.Phone}</td>
                            </tr>
                        </template>
                    </tbody>
                </table>
            </template>
            <template if:true={onboardingList.error}>
                {onboardingList.error}
            </template>
        </div>
    </lightning-card>
</template>

The error i got when I try to call js function with parameter:

Invalid expression {doSomething(dt.Id)} - LWC1060: Template expression doesn't allow CallExpression

Basically I want to call js function with parameter within iterated record. How can I achieve this in LWC?

3 Answers 3

4

You can pass data using data attributes of HTML elements. You can set multiple data attributes on each elements. For eg.

HTML

<a onclick={getIdVal} data-id={dt.id}>Test</a> 

JS Controller

getIdVal(event){
    event.preventDefault();
    console.log('id => ' + event.target.dataset.id);
}

Here is the live example

2
  • This is work for me as of now, it is also very simple, do you think this way will have bad impact going forward in time other than we use the child components?
    – Rival
    Oct 17, 2019 at 4:13
  • it's simpler than using child components, remember if you need in future you can always convert it to a child component, but again if you have input fields, you can not pass values from the child to parent components without using events. Also, its is very cumbersome to manage `too' many small-small child components. I personally prefer to keep it simple and manageable as long as I can. Oct 17, 2019 at 6:19
1

The best practice would be to create a child component. Then call this new component inside the loop.

The child component will know the Id because it only manages one record. It will also manage the onclick handler.

Child component template

<template>
    <tr id="datarow">
        <td>
            <!-- need to call js function with the parameter 
            <a onclick={doSomething}>
                {!dt.Account.Name}
            </a>
        </td>
        <td>{!dt.Email}</td>
        <td>{!dt.Phone}</td>
    </tr>
</template>

Child component controller

export default class ChildComponent extends LightningElement {
    @api dt;

    doSomething() {
        console.log('clicked: ' + dt.Id);
    }
}

Parent template

<template>
    <lightning-card title="Onboarding" icon-name="action:new_task">
        <div class="slds-m-around_medium">
            <template if:true={onboardingList.data}>
                <table id="tblOnboardingList">
                    <thead>
                        <tr>
                            <th>Name</th>
                            <th>Email</th>
                            <th>Phone</th>
                        </tr>
                    </thead>
                    <tbody>
                        <template for:each={onboardingList.data} for:item="dt" for:index="indexvar">
                            <child-component dt={dt}></child-component>
                        </template>
                    </tbody>
                </table>
            </template>
            <template if:true={onboardingList.error}>
                {onboardingList.error}
            </template>
        </div>
    </lightning-card>
</template>
3
  • This will not work unless you give CSS of display style as table row in child-component. Even after doing that this becomes complicated solution just for knowing the parameter. This would have been simple/good solution in aura. Oct 16, 2019 at 7:50
  • It's just for knowing the parameter at the moment. But it will be more maintenable in the future. Because it's always like this. You start by only needing the Id. Then you want to implement some complexe logic. And finally you need to create a child component because at first you start by by adding a data attribute. So you waist time by rewriting your whole component. Years of experience have shown me that you always end up needing a child component. So, yes, this is indeed the best practice solution. Oct 16, 2019 at 8:21
  • This is maybe the recommended way as the child component can contains the whole object
    – Rival
    Oct 17, 2019 at 4:12
0
modify it like below:

<td>
    <div onClick={doSomething} data-rowParam={dt}>
      {!dt.Account.Name}
     </div>
  </td>`enter code here`


on js end:
doSomething(event)(){
   let incomingData=event.currentTarget.dataset.rowParam;
}

/***********

**the other way is and efficient ways where each row is  a child cmp:
parent html**
 <template for:each={rowdetails} for:item="items" for:index="index">
            <div class="slds-col" key={items.pos} title={items.name} data-currentpos={items.pos}
                onclick={getDataFromParent}>

                <c-cmp-child datafromParent={items}>
                </c-cmp-child>
            </div>
        </template>

parent Js:
getDataFromParent(event){
        let currentdivPos = event.currentTarget.dataset.currentpos;
        let divTitle = event.currentTarget.title;
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .