0

I am getting the above error when trying to update a particular value of an object in memory.

I understand I can not make changes to objects gathered from an @wire property. However, this should not matter in this case because the object I am trying to update is only in runtime memory.

A little more detail; When a new timeWeekItem component is created, it creates a Time Week object in memory. This will not be persisted to the DB until the user is done editing it. Once completed, there will be a save button for the user to press and persist. You can edit the time week hours for each day and associate the Time Week to a particular Job Code.

I am using an event in jobCodeSelect to push an id value to the timeWeekItem component. In the timeWeekItem event handler, I want to associate the Time Week(detail) object to the Job Code(master) object by passing it the Job Code ID.

Here is the JS code for all three components. The hierarchy is as follows:
(parent) timeCardContainer > timeWeekItem > jobSelector (child)

the error is coming from the handleJobCode handler in timeWeekItem.

TimeCardContainer:

import { LightningElement, api, track, wire } from 'lwc';
import { getRecord } from 'lightning/uiRecordApi';
import getTimeWeeks from '@salesforce/apex/TimeCardController.getTimeWeeks';

const timeCardFields = [
    'Time_Card__c.Start_Date__c',
    'Time_Card__c.End_Date__c',
    'Time_Card__c.Sunday__c',
    'Time_Card__c.Monday__c',
    'Time_Card__c.Tuesday__c',
    'Time_Card__c.Wednesday__c',
    'Time_Card__c.Thursday__c',
    'Time_Card__c.Friday__c',
    'Time_Card__c.Saturday__c',
    'Time_Card__c.SundayActive__c',
    'Time_Card__c.MondayActive__c',
    'Time_Card__c.TuesdayActive__c',
    'Time_Card__c.WednesdayActive__c',
    'Time_Card__c.ThursdayActive__c',
    'Time_Card__c.FridayActive__c',
    'Time_Card__c.SaturdayActive__c',
];


/* eslint-disable no-console */

export default class TimeCardContainer extends LightningElement {

    @api recordId;
    @track timeWeekList;
    @track error;

    @wire(getRecord, { recordId: '$recordId', fields: timeCardFields })
    timecard;


    connectedCallback() {
        this.loadTimeWeeks();
    }

    loadTimeWeeks() {
        getTimeWeeks({ recid: this.recordId })
            .then(result => {
                console.log('running apex method');
                this.timeWeekList = result;

            })
            .catch(error => {
                this.error = error;
                console.log('There was an error: ' + this.error);
            });
    }

    addRole() {
        //Add a timeweek object to the timeWeekList

        var newTimeWeek = {};
        var emptyJobCode = {};

        emptyJobCode.Name = '';
        newTimeWeek.Time_Card__r = this.timecard;
        newTimeWeek.Start_Date__c = this.startDate;
        newTimeWeek.Start_Date__c = this.endDate;
        newTimeWeek.Job_Code__r = emptyJobCode;
        newTimeWeek.Total_Hours__c = 0;
        newTimeWeek.Sunday_Hours__c = 0;
        newTimeWeek.Monday_Hours__c = 0;
        newTimeWeek.Tuesday_Hours__c = 0;
        newTimeWeek.Wednesday_Hours__c = 0;
        newTimeWeek.Thursday_Hours__c = 0;
        newTimeWeek.Friday_Hours__c = 0;
        newTimeWeek.Saturday_Hours__c = 0;
        newTimeWeek.SundayActive__c = this.timecard.data.fields.SundayActive__c.value;
        newTimeWeek.MondayActive__c = this.timecard.data.fields.MondayActive__c.value;
        newTimeWeek.TuesdayActive__c = this.timecard.data.fields.TuesdayActive__c.value;
        newTimeWeek.WednesdayActive__c = this.timecard.data.fields.WednesdayActive__c.value;
        newTimeWeek.ThursdayActive__c = this.timecard.data.fields.ThursdayActive__c.value;
        newTimeWeek.FridayActive__c = this.timecard.data.fields.FridayActive__c.value;
        newTimeWeek.SaturdayActive__c = this.timecard.data.fields.SaturdayActive__c.value;

        this.timeWeekList.push(newTimeWeek);
    }

    //getter methods
    get startDate() {
        let d = new Date(this.timecard.data.fields.Start_Date__c.value);
        return d.getUTCMonth() + 1 + '/' + d.getUTCDate() + '/' + d.getFullYear();
    }

    get endDate() {
        let d = new Date(this.timecard.data.fields.End_Date__c.value);
        return d.getUTCMonth() + 1 + '/' + d.getUTCDate() + '/' + d.getFullYear();
    }

    get sunday() {
        let d = new Date(this.timecard.data.fields.Sunday__c.value);
        return d.getUTCMonth() + 1 + '/' + d.getUTCDate() + '/' + d.getFullYear();
    }

    get monday() {
        let d = new Date(this.timecard.data.fields.Monday__c.value);
        return d.getUTCMonth() + 1 + '/' + d.getUTCDate() + '/' + d.getFullYear();
    }

    get tuesday() {
        let d = new Date(this.timecard.data.fields.Tuesday__c.value);
        return d.getUTCMonth() + 1 + '/' + d.getUTCDate() + '/' + d.getFullYear();
    }

    get wednesday() {
        let d = new Date(this.timecard.data.fields.Wednesday__c.value);
        return d.getUTCMonth() + 1 + '/' + d.getUTCDate() + '/' + d.getFullYear();
    }

    get thursday() {
        let d = new Date(this.timecard.data.fields.Thursday__c.value);
        return d.getUTCMonth() + 1 + '/' + d.getUTCDate() + '/' + d.getFullYear();
    }

    get friday() {
        let d = new Date(this.timecard.data.fields.Friday__c.value);
        return d.getUTCMonth() + 1 + '/' + d.getUTCDate() + '/' + d.getFullYear();
    }

    get saturday() {
        let d = new Date(this.timecard.data.fields.Saturday__c.value);
        return d.getUTCMonth() + 1 + '/' + d.getUTCDate() + '/' + d.getFullYear();
    }
}

timeWeekItem:

import { LightningElement, api } from 'lwc';

//import TimeWeek from '@salesforce/schema/TimeWeek';

/* eslint-disable no-console */

export default class TimeWeekItem extends LightningElement {

    //----------------PROPERTIES--------------
    @api
    timeweek;



    //----------------HANDLERS----------------
    handleJobCode(event){
         console.log('new attempt');
         this.timeweek.Job_Code__r.id = event.detail;
         console.log(this.timeweek.Job_Code__r.id);


    }




    //----------------GETTERS----------------
    //Get total hours for this time week
    get totalHours() {
        return this.timeweek.Total_Hours__c;
    }

    //Check to see if the day is active. This is used to grey out certian days
    get sundayActive() {
        return !this.timeweek.SundayActive__c;
    }
    get mondayActive() {
        return !this.timeweek.MondayActive__c;
    }
    get tuesdayActive() {
        return !this.timeweek.TuesdayActive__c;
    }
    get wednesdayActive() {
        return !this.timeweek.WednesdayActive__c;
    }
    get thursdayActive() {
        return !this.timeweek.ThursdayActive__c;
    }
    get fridayActive() {
        return !this.timeweek.FridayActive__c;
    }
    get saturdayActive() {
        return !this.timeweek.SaturdayActive__c;
    }

    //Get the current hours logged for each day of the time week
    get sundayHours() {
        return this.timeweek.Sunday_Hours__c;
    }
    get mondayHours() {
        return this.timeweek.Monday_Hours__c;
    }
    get tuesdayHours() {
        return this.timeweek.Tuesday_Hours__c;
    }
    get wednesdayHours() {
        return this.timeweek.Wednesday_Hours__c;
    }
    get thursdayHours() {
        return this.timeweek.Thursday_Hours__c;
    }
    get fridayHours() {
        return this.timeweek.Friday_Hours__c;
    }
    get saturdayHours() {
        return this.timeweek.Saturday_Hours__c;
    }

    //Get the job code for the time week
    get jobCode() {
        return this.timeweek.Job_Code__r.Name;
    }




}

JobCodeSelector:

import { LightningElement, track, api } from 'lwc';
import getJobCodes from '@salesforce/apex/TimeCardController.getJobCodes';

/* eslint-disable no-console */

export default class JobCodeSelect extends LightningElement {

    //Check to see if the Job Code is editable or not
    @track
    selected = false;


    //Id of the Job Code
    @api
    jobCodeId;

    @api
    selectiondata = '';

    //List of possible Job Codes
    @track
    jobCodeList;

    //List of possible Job Codes
    @track
    jobCodeListWithId;

    //Init and check to see if there is already a Job Code selected
    connectedCallback() {
        console.log('selectiondata: ' + this.selectiondata);
        if (this.selectiondata !== '') {
            this.selected = true;
        }
        //query for avilable jobcodes
        getJobCodes()
            .then(result => {
                this.jobCodeList = [];
                this.jobCodeListWithId = [];
                for (let i = 0; i < result.length; i++) {

                    this.jobCodeList.push({ label: result[i].Name, value: result[i].Name });
                    this.jobCodeListWithId.push({ name: result[i].Name, id: result[i].Id });
                }
                console.log(this.jobCodeList);
            })
            .catch(error => {
                this.error = error;
            });
    }


    //Once selected, push the new Job Code up to the Time Week object in memory via an event. 
    //Only persist when the Save or Save/submit button is pushed
    handleChange(event) {
        this.selected = true;
        this.selectiondata = event.detail.value;

        for (let i = 0; i < this.jobCodeListWithId.length; i++) {
            if (this.jobCodeListWithId[i].name === event.detail.value) {
                this.jobCodeId = this.jobCodeListWithId[i].id;
            }
        }
        //create event and send job code id to time week
        const jobCodeSelected = new CustomEvent("jobcodetotimeweek", {
            detail: this.jobCodeId
        });

        // Dispatches the event.
        this.dispatchEvent(jobCodeSelected);
    }
}
2

This behaviour is due to the caching of timeweek property (that you are providing from the parent component).

Try this: Copy(deep clone) the object into some variable and perform your change.

handleJobCode(event){
     console.log('new attempt');
     let tempTimeWeek = JSON.parse(JSON.stringify(this.timeweek)); //... deep clone object
     tempTimeWeek.Job_Code__r.id = event.detail;
     this.timeweek = tempTimeWeek;
     console.log(this.timeweek.Job_Code__r.id);
}
2
  • This worked! Thank you. Quick follow up question: Why do we have to clone the entire object rather than updating a single field? I am new to LWC so any insight would be greatly appreciated. – Rory Feb 6 '20 at 19:46
  • 2
    @Rory Lots of good reading on this question that explains why and other ways it can be fixed. – sfdcfox Feb 6 '20 at 21:19

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.