0

LWC - All items in the list renders again in HTML table (For : Each Iterative) even if particular list element belonging to particular ID got changed. Please could someone let me know how to limit only that particular list element to render which got changed.

Example: Data from Apex

this.result=[{Id:'01',Name:'Tom',Age:'23'},{Id:'02',Name:'Mike',Age:'21'},{Id:'03',Name:'Harry',Age:'24'},{Id:'04',Name:'Sam',Age:'25'}]

How is it possible to render in the for:each iterative only that list element that got changed. Example I changed Age of Sam to 20 so I want only that element(Id:'04',Name:'Sam',Age:'25'}) to render not others.

Thanks

*************EDITED EDITED EDITED ****************************

@sfdxfox - Excuse me may be my ask is not clear. Let me give more details of my requirement. I am trying to implement custom tree grid where in child rows will be shown beneath the parent rows on click of a button available on the parent row.

I am looking for a way by which when I click the button, only that particular parent row is rendered and not the rest of the parent row. Suppose I click button on parent row no 1, then a JS handler is called which modifies the list for row 1 an in turn I expect the framework renders only the changed list element in the markup.

What I observe is the whole list gets rendered which results in the for:each directive executes for all the elementsenter image description here in the list

PFB code:

HTML CODE : 

<template>
<lightning-quick-action-panel header="Create Incident Parts">
<div class="slds-p-around_none slds-m-top_x-small slds-m-bottom_large slds-m-horizontal_none modalBodyy">

<lightning-card>          
<div class="slds-m-around_medium">
<table class="slds-table slds-table_cell-buffer slds-table_bordered" aria-labelledby="element-with-table-label other-element-with-table-label">
    <thead>
        <tr class="slds-line-height_reset">
            <th class="" scope="col">
                <div class="slds-truncate" title="Part Number">Part Number</div>
            </th>
            <th class="" scope="col">
                <div class="slds-truncate" title="Part Name">Part Name</div>
            </th>
            <th class="" scope="col">
                <div class="slds-truncate" title="Failed Parts Quantity">Failed Parts Quantity</div>
            </th>                             
            
            <th class="" scope="col">
                <div class="slds-truncate" title="Number Requested">Number Requested</div>
            </th>

            <th class="" scope="col">                                    
                <div class="slds-truncate" title="Number Sent">Number Sent</div>
            </th>

            <th class="" scope="col">                                    
                <div class="slds-truncate" title="No. Parts Returned">No. Parts Returned</div>
            </th>
    
            <th class="" scope="col">                                    
                <div class="slds-truncate" title=""></div>
            </th>
        </tr>
    </thead>
    <tbody>
        <template for:each={records} for:item="obj" for:index="index">
            <tr class="inputRows" key={obj.Id}>
                <td data-label="Part Number" scope="row" data-id={obj.Id}>
                    <lightning-input type="text" class="fields"  variant="label-hidden" label='Part Number' name="PartNumber" value={obj.Part_Number__c} data-id={obj.Id} readonly ></lightning-input>                                        
                </td>   
                <td data-label="Part Name" scope="row" data-id={obj.Id}>
                    <lightning-input type="text" class="fields" variant="label-hidden" label="Part Name" name="PartName" value={obj.Part_Name__c} data-id={obj.Id} readonly></lightning-input>
                </td>
                <td data-label="Failed Parts Quantity" scope="row" data-id={obj.Id}>
                    <lightning-input type="text" class="fields" variant="label-hidden" label="Failed Parts Quantity" name="FailedPartsQuantity" value={obj.Quantity__c} data-id={obj.Id} readonly></lightning-input>
                </td>
            
                    
                    <td data-label="Number Requested" scope="row" data-id={obj.Id}>
                    <lightning-input type="text" class="fields" variant="label-hidden" label="Number Requested" name="NumberRequested" value={obj.Number_Parts_Requested__c} data-id={obj.Id} readonly></lightning-input>
                    </td>
            
            
                    <td data-label="Number Sent" scope="row" data-id={obj.Id}>                                        
                    <lightning-input type="text" class="fields" variant="label-hidden" label="Number Sent" name="NumberSent" value={obj.Number_Parts_Sent__c} data-id={obj.Id} readonly></lightning-input>
                    </td>

                    <td data-label="No. Parts Returned" scope="row" data-id={obj.Id}>
                    <lightning-input type="text" class="fields" variant="label-hidden" label="No. Parts Returned" name="NoPartsReturned" value={obj.Total_Number_of_Returned_Parts__c} data-id={obj.Id} readonly></lightning-input>
                    
                    </td>

                    <!-- Chevron Icon -->
    <!-- If Chevron Icon button clicked, show the Child header and child rows for the particular clicked parent row-->

                    <td scope="row"  data-label="" data-id={obj.Id}>
                <lightning-button-icon icon-name="utility:chevronright"  onclick={handleClick} data-id={obj.Id} data-index={index} >
                </lightning-button-icon>
                  </td>
            </tr>            
                
            <tr class="slds-line-height_reset"  key={obj.Id}>
                
                <th class="" scope="col" data-id={obj.Id}>
                    <div class="slds-truncate" title="" data-id={obj.Id}></div>
                </th>
                <th class="" scope="col" data-id={obj.Id}>
                    <div class="slds-truncate" title="Part Number" >Part Number</div>
                </th>
                <th class="" scope="col" data-id={obj.Id}>
                    <div class="slds-truncate" title="Part Name" >Part Name</div>
                </th>
                <th class="" scope="col" data-id={obj.Id}>
                    <div class="slds-truncate" title="Failed Parts Quantity">Failed Parts Quantity</div>
                </th>                             
                
                <th class="" scope="col" data-id={obj.Id}>
                    <div class="slds-truncate" title="VIN">VIN</div>
                </th>
            
            </tr>

            <template for:each={records_child} for:item="objchild">
                
                <tr class="inputRows" key={objchild.Id}>
                    
                    <td data-label="" scope="row" data-id={objchild.Id}>                                                                                    
                    </td>   

                    <td data-label="Part Number" scope="row" data-id={objchild.Id} >                                        
                        <lightning-input type="text" class="fields"  variant="label-hidden" label='Part Number' name="PartNumber" value={objchild.Part_Number__c} data-id={objchild.Id} readonly ></lightning-input>                                        
                    </td>   
                    <td data-label="Part Name" scope="row" data-id={objchild.Id}>
                        <lightning-input type="text" class="fields" variant="label-hidden" label="Part Name" name="PartName" value={objchild.Part_Name__c} data-id={objchild.Id} readonly></lightning-input>
                    </td>
                    <td data-label="Failed Parts Quantity" scope="row" data-id={objchild.Id}>
                        <lightning-input type="text" class="fields" variant="label-hidden" label="Failed Parts Quantity" name="FailedPartsQuantity" value={objchild.Quantity__c} data-id={objchild.Id} readonly></lightning-input>
                    </td>
                
                        
                        <td data-label="VIN" scope="row" data-id={objchild.Id}>
                        <lightning-input type="text" class="fields" variant="label-hidden" label="VIN" name="VIN" value={objchild.VIN__c} data-id={objchild.Id} onchange={updateValues}></lightning-input>
                        </td>
                
                    
                    </tr>                
                </template> 
        </template> 
            
        
    </tbody>
</table>
</div>
</lightning-card>
</div>
<div slot="footer">
<lightning-button variant="neutral" label="Cancel" onclick={closeAction}></lightning-button> &nbsp;
<lightning-button variant="brand" label="Save" onclick={handleSaveAction} disabled={isDisable}></lightning-button>
</div>
</lightning-quick-action-panel>
</template>

JS CODE:

---Fetching the data from controller


@wire(fetchIP,{Case_Id:'$recordId'})
caseHandler(value){
    this.wiredActivities = value;
    const { data, error } = value;    
    if(data){                           
       this.records = JSON.parse(JSON.stringify(data));

for(var i=0;i<this.records.length;i++)
{
    this.records[i] = Object.assign({isHeaderDisplayed:false}, this.records[i]);    
}
    }
}


----On click of the button, execute below handler to update the array (records) to set the field 'isHeaderDisplayed' value for the clicked parent row
----- here I expect that once the list/array (which is records) is changed, the framework only renders the particular parent row on the markup.
------ But that ia not happening, is it the expected behavior

handleClick(event) {
this.rowName = event.target.dataset.id;

var foundelement = this.records.find(ele => ele.Id ==  event.target.dataset.id);



if(foundelement.isHeaderDisplayed==false)
{
    foundelement.isHeaderDisplayed=true;
}

else
{
    foundelement.isHeaderDisplayed=false;
}

    fetchRP({ InciPart: this.rowName })
    .then((result) => {
        this.records_child =JSON.parse(JSON.stringify(result));         
});
}
5
  • That's how LWC is supposed to work. What are you observing?
    – sfdcfox
    Oct 7, 2022 at 20:50
  • Thanks for the quick reply I got the below statements from Salesforce documentation that states otherwise. Whenever we use for:each or Iterator we need to use key directive on the element on which we are doing iteration. Key gives unique id to each item. Remember, without key we cannot do iteration. When a list changes, the framework uses the key to rerender only the item that changed. It is used for performance optimization and isn’t reflected in the DOM at run time. Oct 7, 2022 at 21:06
  • That's what is expected. I'm not sure what you're trying to ask? Only the elements which are dirty should be updating.
    – sfdcfox
    Oct 7, 2022 at 21:32
  • How are you declaring the property? Are you ensuring it is initialized, in the declaration, as an array to hint to the LWC compiler how to handle tracking changes?
    – Phil W
    Oct 7, 2022 at 23:01
  • @sfdcfox Phil W - Please refer the edits made with clear explanation. Oct 8, 2022 at 7:36

0

You must log in to answer this question.

Browse other questions tagged .