3

I'd like to understand the usefulness of the method JSON.parse in the JS file of a lwc when we want to perform certain actions on a list of objects retrieved from our apex controller. I give you an example. I have implemented the sorting functionality on a lightning datatable in a lwc. but my problem is when I don't use the JSON.parse method when I get all the data, I get an empty proxy. Here is the the output when I'm debugging:

enter image description here

But when I use the JSON.parse method when I get the data I want to sort, I get and I see all the data when I'm debugging. Here is the output for this case:

enter image description here

Can someone help me please to understand why we can't see the data without the JSON.pase method and why without the JSON.parse method it doesn't work?

here is the html template:

      <lightning-datatable key-field="Id" 
                           data={opportunities} 
                           columns={columns}  
                           onsort={updateColumnSorting} 
                           sorted-by={sortedBy} 
                           sorted-direction={sortedDirection}>
      </lightning-datatable>

the js file:

import { LightningElement ,wire,track} from 'lwc';
import getAllOpps from '@salesforce/apex/GetAllOpportunities.getAllOpps';

export default class OpportunityList extends LightningElement {
    @track columns = [
        {
            label: 'Opportunity name',
            fieldName: 'Name',
            type: 'tex',
            sortable: true
        },
        {
            label: 'Stage Name',
            fieldName: 'StageName',
            type: 'text',
            sortable: true
        },
        {
            label: 'Close date',
            fieldName: 'CloseDate',
            type: 'date',
            sortable: true
        }

    ];

    @track error;
    @track opportunities = [];
    @track sortedBy;
    @track sortedDirection = 'asc';


    @wire(getAllOpps)
    wiredOpps({error,data}) {
        if (data) {
            this.opportunities = data;
            this.error = undefined;
        } else if (error) {
            this.error = error;
            this.opportunities = undefined;
        }
    }   

    sortData(fieldName, sortDirection){

        //let data = JSON.parse(JSON.stringify(this.opportunities));
        let data = this.opportunities;
        //function to return the value stored in the field
        const key = (a) => {
            let fieldValue = a[fieldName] ? (typeof a[fieldName] === 'string' ? a[fieldName].toLowerCase() : a[fieldName]) : '';
           return fieldValue; 
        }
        let reverse = sortDirection === 'asc' ? 1: -1;

        //set sorted data to opportunities attribute
        this.opportunities = data.sort((a,b) => {
            return reverse * ((key(a) > key(b)) - (key(b) > key(a)));
        });          

    }

    updateColumnSorting(event){
        this.sortedBy = event.detail.fieldName;
        this.sortedDirection = event.detail.sortDirection;
        this.sortData(this.sortedBy,this.sortedDirection);       
    }   

}

And the apex controller:

public with sharing class GetAllOpportunities {
   @AuraEnabled(cacheable=true)
    public static List<Opportunity> getAllOpps() {

        return [SELECT Id, Name ,StageName, CloseDate FROM Opportunity Limit 10];
    }

}


Thanks in advance!

2 Answers 2

5

The behavior you are seeing is because of Salesforce feature called lightning locker.

Any object in lwc JavaScript will use the proxy object.

https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/security_proxy.htm

It's a security feature that makes debugging difficult but adds additional security.

You don't need to use JSON.stringify and JSON.parse in prod .You can use it for debugging purposes.

Update

Looking into the code , it looks like lockerservice proxy is forcing the object to readonly on datatable . You should report this as a bug to salesforce .

11
  • Thank you @Mohith Shrivastava for your reply. But is it normal to get a proxy with an empty array?
    – dibocor
    Commented May 26, 2019 at 16:49
  • No that's not normal.Do you see the data on the UI ? Commented May 26, 2019 at 16:56
  • Can you share the code snippet so we can see what's going on ? Commented May 26, 2019 at 16:57
  • 1
    I edited the question and added the code
    – dibocor
    Commented May 26, 2019 at 17:37
  • 1
    ok I added the apex class
    – dibocor
    Commented May 26, 2019 at 18:03
1

Data obtained from a @wire method is immutable, because otherwise you could corrupt the cache. You do need to make a copy (e.g. via JSON.stringify/JSON.parse) if you need to modify the array later. Here's what that looks like:

@wire(getAllOpps)
wiredOpps({error,data}) {
    if (data) {
        this.opportunities = [...data];
        this.error = undefined;
    } else if (error) {
        this.error = error;
        this.opportunities = undefined;
    }
}   

Unless you plan on modifying the records in the array, this one change should be sufficient for fixing the problem.

3
  • 1
    Thanks @sfdcfox for your reply. It works but my problem is why I get a proxy with an empty array (the data variable in the sortData method ) when I click on the header for sorting the data
    – dibocor
    Commented May 27, 2019 at 17:09
  • 1
    The issue is if design does not give you the felxibilty to make the object available for other functions it's a design flaw . Commented May 27, 2019 at 17:11
  • At least with standard components like lightning datatable I was hoping we could loop and perform operations Commented May 27, 2019 at 17:12

You must log in to answer this question.

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