Skip to main content
Adding formatting, clarifying the issue experienced and the solution, and removing some monologue-y stuff
Source Link

I'm new to LWC. And after going through the entire "Build Lightning Web Components" trail, I must still be missing something fundamental about how the uiRecordApi getRecordgetRecord method works, or maybe I just don't understand Javascript half as well as I think.

When using @wire(getRecord, ...)@wire(getRecord, ...), I get back an object with data as expected, except. But I can't access that data in the way I'm used to. Dot notation, Object.keys()Object.keys(), and even JSON.parse(JSON.stringify(Object))JSON.parse(JSON.stringify(Object)) are failing in ways that suggest that the object is undefined in some cases.

import { LightningElement, api, track, wire } from 'lwc';
import { getRecord, getFieldValue } from 'lightning/uiRecordApi';

// ...

import APP_NAME from '@salesforce/schema/Application__c.Name';
// etc...

export default class myApplicationThing extends LightningElement {
    @api recordId; // Application__c.Id
    @track app; // Application__c record
    @track appName;
    // ...
    @wire(getRecord, { recordId: '$recordId', fields })
    loadRecord ({ error, data })   {        
        if (data) {
            this.app = data;
            this.error = undefined;
            this.appName = getFieldValue(data, APP_NAME); // I can use the value
            // of appName just fine if I get it this way, e.g. with {appName}
            // in the HTML template
            // ...
        } else if (error) {
            // ...
        }
    }
    
    // Called from a {testMe} in the HTML template
    get testMe() {
        console.log(this.app); // returns a Proxy
        console.log(JSON.stringify(this.app)); // returns a JSON as expected:

        /* 
        {
            "apiName": "Application__c",
            "childRelationships": {},
            "fields": {
                "Name": {
                    "displayValue": null,
                    "value": "A-0801096"
                },
                "Service_Area__c": {
                    "displayValue": null,
                    "value": "UT"
                },
                ...
            },
            ...
        } */
        
        console.log(this.app.fields.Name.value); // throws error:

        /* afterRender threw an error in 'c:crmApplication'myApplicationThing' 
        [Cannot read property 'fields' of undefined] */

        console.log(this.app.keys()); // throws error:

        /* Cannot read property 'keys' of undefined */

        console.log(JSON.parse(JSON.stringify(this.app))); // throws error:

        /* Unexpected token u in JSON at position 0 */
        
        return '?!';
    }

I could theoretically use getFieldValuegetFieldValue to get all the field values on my record, but I'm building up a large form with lots of fields, and trying to nest components within components according to best practice. So in reality this would mean calling out each separate field a whole bunch of times in different places in a way that is super verbose and hard to maintain. I'd much rather pass an object around vs. passing around dozens of primitives.

By the time I got the answer from @BritishBoyinDC (well done, sir!), I had been pondering the nature of ansync wired data, and I solved my problem by wrapping the entire component HTML like so:

Everything inside that if:true directive that relies on the wired record data holds it horses and waits for the data to show up. :-)

By the way, console.log(this.app) and console.log(JSON.stringify(this.app)) work because you can both log and JSON-stringify an undefined object in JavaScript without incurring an error. On the other hand, if you try to access properties on an undefined object, an error comes up.

I'm new to LWC. And after going through the entire "Build Lightning Web Components" trail, I must still be missing something fundamental about how the uiRecordApi getRecord method works, or maybe I just don't understand Javascript half as well as I think.

When using @wire(getRecord, ...), I get back an object with data as expected, except I can't access that data in the way I'm used to. Dot notation, Object.keys(), and even JSON.parse(JSON.stringify(Object)) are failing.

import { LightningElement, api, track, wire } from 'lwc';
import { getRecord, getFieldValue } from 'lightning/uiRecordApi';

// ...

import APP_NAME from '@salesforce/schema/Application__c.Name';
// etc...

export default class myApplicationThing extends LightningElement {
    @api recordId; // Application__c.Id
    @track app; // Application__c record
    @track appName;
    // ...
    @wire(getRecord, { recordId: '$recordId', fields })
    loadRecord ({ error, data })   {        
        if (data) {
            this.app = data;
            this.error = undefined;
            this.appName = getFieldValue(data, APP_NAME); // I can use the value
            // of appName just fine if I get it this way, e.g. with {appName}
            // in the HTML template
            // ...
        } else if (error) {
            // ...
        }
    }
    
    // Called from a {testMe} in the HTML template
    get testMe() {
        console.log(this.app); // returns a Proxy
        console.log(JSON.stringify(this.app)); // returns a JSON as expected:

        /* 
        {
            "apiName": "Application__c",
            "childRelationships": {},
            "fields": {
                "Name": {
                    "displayValue": null,
                    "value": "A-0801096"
                },
                "Service_Area__c": {
                    "displayValue": null,
                    "value": "UT"
                },
                ...
            },
            ...
        } */
        
        console.log(this.app.fields.Name.value); // throws error:

        /* afterRender threw an error in 'c:crmApplication' 
        [Cannot read property 'fields' of undefined] */

        console.log(this.app.keys()); // throws error:

        /* Cannot read property 'keys' of undefined */

        console.log(JSON.parse(JSON.stringify(this.app))); // throws error:

        /* Unexpected token u in JSON at position 0 */
        
        return '?!';
    }

I could theoretically use getFieldValue to get all the field values on my record, but I'm building up a large form with lots of fields, and trying to nest components within components according to best practice. So in reality this would mean calling out each separate field a whole bunch of times in different places in a way that is super verbose and hard to maintain. I'd much rather pass an object around vs. passing around dozens of primitives.

By the time I got the answer from @BritishBoyinDC (well done, sir!), I had been pondering the nature of ansync wired data, and I solved my problem by wrapping the entire component HTML like so:

Everything inside that if:true directive that relies on the wired record data holds it horses and waits for the data to show up. :-)

I'm new to LWC. And after going through the entire "Build Lightning Web Components" trail, I must still be missing something fundamental about how the uiRecordApi getRecord method works.

When using @wire(getRecord, ...), I get back an object with data as expected. But I can't access that data in the way I'm used to. Dot notation, Object.keys(), and even JSON.parse(JSON.stringify(Object)) are failing in ways that suggest that the object is undefined in some cases.

import { LightningElement, api, track, wire } from 'lwc';
import { getRecord, getFieldValue } from 'lightning/uiRecordApi';

// ...

import APP_NAME from '@salesforce/schema/Application__c.Name';
// etc...

export default class myApplicationThing extends LightningElement {
    @api recordId; // Application__c.Id
    @track app; // Application__c record
    @track appName;
    // ...
    @wire(getRecord, { recordId: '$recordId', fields })
    loadRecord ({ error, data })   {        
        if (data) {
            this.app = data;
            this.error = undefined;
            this.appName = getFieldValue(data, APP_NAME); // I can use the value
            // of appName just fine if I get it this way, e.g. with {appName}
            // in the HTML template
            // ...
        } else if (error) {
            // ...
        }
    }
    
    // Called from a {testMe} in the HTML template
    get testMe() {
        console.log(this.app); // returns a Proxy
        console.log(JSON.stringify(this.app)); // returns a JSON as expected:

        /* 
        {
            "apiName": "Application__c",
            "childRelationships": {},
            "fields": {
                "Name": {
                    "displayValue": null,
                    "value": "A-0801096"
                },
                "Service_Area__c": {
                    "displayValue": null,
                    "value": "UT"
                },
                ...
            },
            ...
        } */
        
        console.log(this.app.fields.Name.value); // throws error:

        /* afterRender threw an error in 'c:myApplicationThing' 
        [Cannot read property 'fields' of undefined] */

        console.log(this.app.keys()); // throws error:

        /* Cannot read property 'keys' of undefined */

        console.log(JSON.parse(JSON.stringify(this.app))); // throws error:

        /* Unexpected token u in JSON at position 0 */
        
        return '?!';
    }

I could theoretically use getFieldValue to get all the field values on my record, but I'm building up a large form with lots of fields, and trying to nest components within components according to best practice. So in reality this would mean calling out each separate field a whole bunch of times in different places in a way that is super verbose and hard to maintain. I'd much rather pass an object around vs. passing around dozens of primitives.

By the time I got the answer from @BritishBoyinDC, I had been pondering the nature of ansync wired data, and I solved my problem by wrapping the entire component HTML like so:

Everything inside that if:true directive that relies on the wired record data holds it horses and waits for the data to show up. :-)

By the way, console.log(this.app) and console.log(JSON.stringify(this.app)) work because you can both log and JSON-stringify an undefined object in JavaScript without incurring an error. On the other hand, if you try to access properties on an undefined object, an error comes up.

added 450 characters in body
Source Link

Solution

By the time I got the answer from @BritishBoyinDC (well done, sir!), I had been pondering the nature of ansync wired data, and I solved my problem by wrapping the entire component HTML like so:

<template>
    <template if:true={app}>
        ...
    </template>
</template>

Everything inside that if:true directive that relies on the wired record data holds it horses and waits for the data to show up. :-)

Solution

By the time I got the answer from @BritishBoyinDC (well done, sir!), I had been pondering the nature of ansync wired data, and I solved my problem by wrapping the entire component HTML like so:

<template>
    <template if:true={app}>
        ...
    </template>
</template>

Everything inside that if:true directive that relies on the wired record data holds it horses and waits for the data to show up. :-)

Source Link

LWC: Can't access field values from @wire + uiRecordApi/getRecord

I'm new to LWC. And after going through the entire "Build Lightning Web Components" trail, I must still be missing something fundamental about how the uiRecordApi getRecord method works, or maybe I just don't understand Javascript half as well as I think.

When using @wire(getRecord, ...), I get back an object with data as expected, except I can't access that data in the way I'm used to. Dot notation, Object.keys(), and even JSON.parse(JSON.stringify(Object)) are failing.

I have in my Javascript controller:

import { LightningElement, api, track, wire } from 'lwc';
import { getRecord, getFieldValue } from 'lightning/uiRecordApi';

// ...

import APP_NAME from '@salesforce/schema/Application__c.Name';
// etc...

export default class myApplicationThing extends LightningElement {
    @api recordId; // Application__c.Id
    @track app; // Application__c record
    @track appName;
    // ...
    @wire(getRecord, { recordId: '$recordId', fields })
    loadRecord ({ error, data })   {        
        if (data) {
            this.app = data;
            this.error = undefined;
            this.appName = getFieldValue(data, APP_NAME); // I can use the value
            // of appName just fine if I get it this way, e.g. with {appName}
            // in the HTML template
            // ...
        } else if (error) {
            // ...
        }
    }
    
    // Called from a {testMe} in the HTML template
    get testMe() {
        console.log(this.app); // returns a Proxy
        console.log(JSON.stringify(this.app)); // returns a JSON as expected:

        /* 
        {
            "apiName": "Application__c",
            "childRelationships": {},
            "fields": {
                "Name": {
                    "displayValue": null,
                    "value": "A-0801096"
                },
                "Service_Area__c": {
                    "displayValue": null,
                    "value": "UT"
                },
                ...
            },
            ...
        } */
        
        console.log(this.app.fields.Name.value); // throws error:

        /* afterRender threw an error in 'c:crmApplication' 
        [Cannot read property 'fields' of undefined] */

        console.log(this.app.keys()); // throws error:

        /* Cannot read property 'keys' of undefined */

        console.log(JSON.parse(JSON.stringify(this.app))); // throws error:

        /* Unexpected token u in JSON at position 0 */
        
        return '?!';
    }

I could theoretically use getFieldValue to get all the field values on my record, but I'm building up a large form with lots of fields, and trying to nest components within components according to best practice. So in reality this would mean calling out each separate field a whole bunch of times in different places in a way that is super verbose and hard to maintain. I'd much rather pass an object around vs. passing around dozens of primitives.

Also... I read this thread, and while Kevin's answer seems to be getting at something, I'm still thrown by the fact that my first 2 console log examples above do return the value I was expecting.

Am I way off the deep end? What's the right way to go about this?