6

I am calling an external system from an @wire method and it returns a json string. When I parse the json into an object I am able to use dot notation to access fields from the json object in JS but when I set it to an @track variable I am unable to use dot notation in the HTML to access the fields from the json object.

JS:

import { LightningElement, track, wire } from 'lwc';
import getProfile from '@salesforce/apex/SFG_ECC_GP_ProfileController.getProfile';
export default class GpCaseScreenProfile extends LightningElement {
    @track profile; 
@wire(getProfile)
        handleJson({ error, data} ){
            if (data) {
                this.profile = JSON.parse(data);
                console.log(this.profile.Name.First); // THIS WORKS
            } else if (error) {

                this.error = error;
                this.profile = undefined;
                console.log('ERROR is:', error + 'profile is:', this.profile );
            }
        }
    }

HTML:

<template>
    {profile.Name.First}
</template>

The above html throws an error saying Name is undefined

if I just do

<template>
    {profile}
</template>

it renders as

[Object Object]

Any thoughts on how to inform the HTML that profile is a custom json object?

I also tried using square bracket notation profile['Name']['First'] but that wouldn't compile.

2 Answers 2

6

That is because HTML will load before your external call finishes and Profile will be undefined before getting response and so I would suggest to use conditional rendering in HTML itself so that you can fetch the values directly instead of increasing Javascript code for implementing multiple getters.

HTML:

<template>
    <template if:true={profile}>
        {profile.Name.First}
        {profile.Name.Last}
        {profile.Email}
        {profile.Phone}
    </template>
</template>

As you see, there is no need of implementing 4 getters in JS

2

Change your template to use a getter that checks for null down the object tree

in JS

get name(){
let returnValue = '';

if(this.profile && this.profile.Name && this.profile.Name.First){
  returnValue = this.profile.Name.First;
}
return returnValue;
}

in html

<template>
    {name}
</template>

What's happening is you are looking for the name on profile before the browser has had a chance to make the call to the service so there is no name to get yet.

Reference: https://wipdeveloper.com/lwc-getting-data-with-the-wire-service/

3
  • This will increase the code of JS multifold, I have suggested different way of handling. You can have look at this Sep 25, 2019 at 4:42
  • That solution looks like it works great as well but it moved the null checking to the template. If the profile is used in more locations than one block there would be multiple <template if:true={profile}> in the HTML making it more difficult to read at a glance. Unless They want the entire template to load nothing and then pop-in after the call finishes this would cause the HTML to increase multifold. Sep 25, 2019 at 14:31
  • That is how it is supposed to be implemented according to this doc. Even if profile fields are in multiple places, all that should be in single if:true (very rare scenario) Sep 25, 2019 at 14:39

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.