+ Start a Discussion
Matt Eck 15Matt Eck 15 

Lightning Web Component - Cannot update field on wrapper class in JS

Hello All,
I am currently looking into Lightning Web Components and have hit a wall. I have a wire decorator that calls to an apex function returning a wrapper class. This Wrapper actually contains a Wrapper that contains a Wrapper, so it is nested 3 times. What I would like to do is updated a field on the 3rd Wrapper when a checkbox is checked or unchecked.

important HTML:
<template if:true={progWrap.progList}>
                    <template for:each = {progWrap.progList} for:item = "prog">
                        <tr key = {prog.progAuth.Id} >
                            <td>{prog.programName}</td>
                            <td>{prog.programCountry}</td>
                            <template if:true={prog.checkboxes}>
                                <template for:each={prog.checkboxes} for:item="checkbox">
                                    <template if:true={checkbox.visible}>
                                        <td key={checkbox.section}><lightning-input type="checkbox" value={checkbox.section} checked={checkbox.checked} data-prog-name ={prog.programName} onchange={handleCheckboxChange}></lightning-input></td>
                                    </template>
                                    <template if:false={checkbox.visible}>
                                        <td key={checkbox.section}>-</td>
                                    </template>
                                </template>
                            </template>
                        </tr>
                    </template>
                </template>

JS:
import { LightningElement, api, track, wire } from 'lwc';
import initWrapper from '@salesforce/apex/programAuthComponentController.initWrapper';

export default class programAuthWebComponent extends LightningElement {
    
    @api recordId;
    @track progWrap;
    @track error;
    @wire(initWrapper, {accId: '$recordId'}) 
    progWrapper({
        error,
        data
    }){
        if(data){
            this.progWrap = data;
        }
        else{
            this.error = error;
        }
    }

    handleCheckboxChange(event){
        var checkValue = event.target.value;
        var checkValue2;
        var programName = event.target.dataset.progName;

        if(checkValue === 'Spring / Semester 1'){
            checkValue = 'Spring';
            checkValue2 = 'Semester 1';
        }
        else if(checkValue === 'Fall / Semester 2'){
            checkValue = 'Fall';
            checkValue2 = 'Semester 2';
        }

        for(let i = 0; i < this.progWrap.progList.length; i++){
            if(this.progWrap.progList[i].programName === programName){
                //console.log(this.progWrap.progList[i].checkboxes.length);
                for(let j = 0; j < this.progWrap.progList[i].checkboxes.length; j++){
                    if(this.progWrap.progList[i].checkboxes[j].section === checkValue){
                        console.log(JSON.stringify(this.progWrap.progList[i].checkboxes[j]));
                        this.progWrap.progList[i].checkboxes[j].checked = true;
                    }
                }
            }
        }
    }
}

Apex Wrappers:
public class wrapperClass{
        @AuraEnabled public List<progAuthWrapperClass> progList{get;set;}
        @AuraEnabled public List<String> sections{get;set;}
        @AuraEnabled public List<String> modifiedSections{get;set;}
    }

    public class progAuthWrapperClass{
        @AuraEnabled public String programName {get;set;}
        @AuraEnabled public String programCountry {get;set;}
        @AuraEnabled public Program_Authorization__c progAuth {get;set;}
        @AuraEnabled public Boolean updated {get;set;}
        @AuraEnabled public Set<String> avaliableTerms {get;set;}
        @AuraEnabled public List<checkboxWrapper> checkboxes {get;set;}
    }

    public class checkboxWrapper{
        @AuraEnabled public Boolean visible {get;set;}
        @AuraEnabled public Boolean checked {get;set;}
        @AuraEnabled public String section {get;set;}
    }

    @AuraEnabled(cacheable=true)
    public static wrapperClass initWrapper(Id accId){
        wrapperClass returnWrapper = new wrapperClass();
        returnWrapper.sections = returnSections();
        returnWrapper.modifiedSections = returnModifiedSections(returnWrapper.sections);
        returnWrapper.progList = returnPrograms(accId);
        return returnWrapper;
    }
The UI Looks like this currently (this is a work in progress):

User-added image

Essentially what we want to have happen is when on of these checkboxes is clicked, it updates the checked boolean on the checkboxWrapper. I thought I could update the this.progWrap.progList[i].checkboxes[j].checked in my for loop but everytime I do this I get an error from salesforce that says this: ['set' on proxy: trap returned falsish for property 'checked'].

This may be too much information but really my question is, what does that mean? and How do I actually update this field?

Thank you all for any help!
marksinfo hydmarksinfo hyd
https://vedatech-dev-ed.lightning.force.com/c/LightningApplication2.app
Matt Eck 15Matt Eck 15
I was able to resolve this issue by managing all data changes server side and pushing them client side rather than the other way around. This works fine and I was able to get past this issue, however I still don't know why this was happening in the first place.
Ajitesh Singh 19Ajitesh Singh 19
Hi Matt,

You can remove @AuraEnabled(cacheable=true) from your apex class and you are good to go.Cacheable= true is used only when the data will not change.
Kent Heberling 24Kent Heberling 24
Removing "@AuraEnabled(cacheable=true)" did not work for me in a similar instance. In fact, the method hadn't been cachable from the start. What I ended up doing:

(1) Create a fields proprerty
@track fields = {};

(2) Initialize it (participant is a single record passed from my wrapper)
connectedCallback() {
// Add ID to fields list, and package as object. This gets around immutable problems
this.fields[ID_FIELD.fieldApiName] = this.participant.Id;
this.fields[STATUS_FIELD.fieldApiName] = this.participant.Status__c;
this.fields[CONTACT_METHOD_FIELD.fieldApiName] = this.participant.Preferred_Contact_Method__c;
this.fields[CONTACT_VALUE_FIELD.fieldApiName] = this.participant.Preferred_Contact_Value__c;
}

(3) Display and update fields as needed
{fields.Id} for example
this.fields[CONTACT_VALUE_FIELD.fieldApiName] = 'some new value';

(4) Used this as an update method
doUpdate(){
const fields = this.fields;
const record = { fields };
updateRecord(record)
.then(() => {
})
.catch(error => {
this.dispatchEvent(
new ShowToastEvent({
title: 'Error creating record',
message: error.body.message,
variant: 'error'
})
);
});
}
 
Prajna Hegde 10Prajna Hegde 10
Resolution from @Ajitesh Singh 19 solved my issue currently
Praveen Kumar R 6Praveen Kumar R 6
Hi @Prajna Hegde 10,

Could you please let us know how were you able to resolve this issue. If possible, can you share the sample snippet.