1

I am trying to resolve 2 issues with an LWC

  1. Render a calculated value in an LWC after the user inputs. After the calculation, render value on correct row. I can see the calculated value in console but never renders in html
  2. Format for:each value. I am only returning a single field value. Right now it renders the value but cannot show label. I would like the formatting to be similar to what I see using lightning-input

HTML

        <template if:true={laborTypeSpecific}>
            <lightning-layout-item size="12" large-device-size="2" padding="around-small">
                <lightning-input name="Days_Per_Crew__c" label="Days per Crew" type="number" value={row.Days_Per_Crew__c} onchange={handleDaysPerCrewChange} required></lightning-input>
            </lightning-layout-item>
            <lightning-layout-item size="12" large-device-size="2" padding="around-small">
                <lightning-input name="Number_of_Crew_Members__c" label="Number Of Crew Members" type="number" value={row.Number_of_Crew_Members__c} onchange={handleNumberOfCrewMembersChange} required></lightning-input>
            </lightning-layout-item>
            <lightning-layout-item>
                <template for:each={hourlyRate} for:item="hr">
                    <lightning-layout-item size="12" large-device-size="2" padding="around-small" key={hr.id}>
                        <div class="titleheadings">Hourly Rate</div>
                                <span>{hr.Hourly_Rate__c}</span>
                    </lightning-layout-item>
                </template>
            </lightning-layout-item>
            <lightning-layout-item size="12" large-device-size="2" padding="around-small">
                <lightning-input name="Labor_Total_Calculated__c" label="Labor Total" type="number" value={row.Labor_Total_Calculated__c}></lightning-input>
            </lightning-layout-item>

        </template>

JS

@api row;
@api projectid;
@track hourlyRate;

laborTypeSpecific;

laborTypeOptions = [];
@wire(getObjectInfo, { objectApiName: ESTIMATE_ITEM_OBJECT })
objectInfo;

@wire(getPicklistValues, {
    recordTypeId: '$objectInfo.data.defaultRecordTypeId', fieldApiName: COST_TYPE_FIELD })
laborTypeOptionsWrapper({ data }) {
    if (data) {
        this.laborTypeOptions = data.values;
    }
}

connectedCallback() {
    getProjectHourlyrate({ paramProjectId : this.projectid })
    .then(result => {
        this.hourlyRate = result;
        this.error = undefined;
    })
    .catch(error => {
        this.error = error;
        this.hourlyRate = undefined;
    })
}

addNewRow() {
    const event = new CustomEvent('addrow');
    this.dispatchEvent(event);
}

removeRow() {
    const event = new CustomEvent('removerow', {
        detail: this.row.id
    });
    this.dispatchEvent(event);
}

handleLaborChange(event) {
    this.row.Cost_Type__c = event.detail.value;
    this.laborTypeSpecific = this.row.Cost_Type__c == 'Labor - Standard' || this.row.Cost_Type__c == 'Labor - Overtime';
}

handleCostTypeChange(event) {
    this.row.Cost_Type__c = event.detail.value;
}

handleDaysPerCrewChange(event) {
    this.row.Days_Per_Crew__c = event.detail.value;
    let numberOfCrew = this.row.Number_of_Crew_Members__c != undefined ? this.row.Number_of_Crew_Members__c : 0;
    this.row.Labor_Total_Calculated__c = this.row.Days_Per_Crew__c * numberOfCrew;
    this.handleChange();
}

handleNumberOfCrewMembersChange(event) {
    this.row.Number_of_Crew_Members__c = event.detail.value;
    let crewDays =  this.row.Days_Per_Crew__c != undefined ? this.row.Days_Per_Crew__c : 0;
    this.row.Labor_Total_Calculated__c = this.row.Number_of_Crew_Members__c * crewDays;
    this.handleChange();
}

1 Answer 1

0

The reactive property might not be updating as expected for the first issue regarding rendering a calculated value in an LWC. In LWC, to make a property reactive, it should be decorated with @track, @api, or be part of an object that is tracked.

Since the row is an @api property, changes to its nested properties won't trigger a re-render unless you replace the whole object or use the @track decorator on a private property.

Below is a modified version of your handleDaysPerCrewChange and handleNumberOfCrewMembersChange methods:

handleDaysPerCrewChange(event) {
   // Clone the current row to a new object to make the change reactive
   let newRow = {...this.row};
   newRow.Days_Per_Crew__c = event.detail.value;
   let numberOfCrew = newRow.Number_of_Crew_Members__c || 0;
   newRow.Labor_Total_Calculated__c = newRow.Days_Per_Crew__c * numberOfCrew;
   this.row = newRow; // Set the row to the new object to trigger reactivity
}

handleNumberOfCrewMembersChange(event) {
   let newRow = {...this.row};
   newRow.Number_of_Crew_Members__c = event.detail.value;
   let crewDays = newRow.Days_Per_Crew__c || 0;
   newRow.Labor_Total_Calculated__c = newRow.Number_of_Crew_Members__c * crewDays;
   this.row = newRow; 
}

You can wrap the value with a lightning-layout-item for the second issue and include a label element.

<template for:each={hourlyRate} for:item="hr">
   <lightning-layout-item key={hr.id}>
      <label class="slds-form-element__label">{hr.label}</label>
      <div class="slds-form-element__control">
        <span>{hr.Hourly_Rate__c}</span>
      </div>
   </lightning-layout-item>
</template>
1
  • Tushar. The calculation is render now. Thank you. I updated the html above. The only issue I am really seeing is the actual text Hourly Rate is lower than the the text. Any thoughts? Commented Apr 3, 2024 at 12:50

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.