0

I am trying to display the account name in the HTML by fetching the data from apex controller. The getter method in the JS file is used to fetch the data from apex using the wire method and return the account name in HTML but the name is not displaying at the moment. What could be the issue?

HTML:

<template>
    <lightning-card title="My Account Record" icon-name="standard:account">
            <div class="slds-m-around_medium">
                <p>My name is : {myname}</p>
            </div>
    </lightning-card>
</template>

JS:

import { LightningElement, wire, api} from 'lwc';
import getRecord from '@salesforce/apex/AccountController.getAccounts';
const FIELDS = [
    'Account.Name',
    'Account.Industry',
    'Account.Rating',
    'Account.Website',
];
export default class FetchDataFromApex extends LightningElement {
    
    
@api recordId;
@wire(getRecord, {recordId: '$recordId', fields: FIELDS}) record;

@api
get myname() {
    return this.record.data.fields.Name.value;
}

@api
get myindustry() {
    return this.record.data.fields.Industry.value;
}

@api
get myrating() {
    return this.record.data.fields.Rating.value;
}

@api
get mywebsite() {
    return this.record.data.fields.Website.value;
}
}

Apex:

public without sharing class AccountController {

    //account controller class
    @AuraEnabled(cacheable = true)
    public static List<Account> getAccounts()
    {
            return [SELECT Id, Name, Industry, Rating, Website, AnnualRevenue FROM Account LIMIT 25];
    }
}

1 Answer 1

3

You're calling an apex method that has no input parameters, but you're passing two params (recordId and fields). Since you already defined the fields in the apex method, you only need the first parameter.

Apex:

public without sharing class AccountController {

    @AuraEnabled(cacheable = true)
    public static List<Account> getAccounts(String recordId) {
        return [SELECT Name, Industry, Rating, Website FROM Account WHERE Id = :recordId];
    }
}

In the JS controller you are using the sintax needed for records retrived via uiRecordApi but you need the one for wired apex method.
Moreover you are getting an array of element, so you cannot do something.data.properties, but you need to specify the index: something.data[index].properties.
Lastly you don't need @api decorator for your properties. Every field used in the template is always reactive.

JS:

import { LightningElement, wire, api} from 'lwc';
import getRecord from '@salesforce/apex/AccountController.getAccounts';

export default class FetchDataFromApex extends LightningElement {
    @api recordId;
    record;

    @wire(getRecord, {recordId: '$recordId'})
    wiredAccount({ error, data }) {
        if (data) {
            this.record = data[0];
        } else if (error) {
            console.log('Something went wrong:', error);
        }
    }

    get myName() {
        return this.record?.Name;
    }

    get myIndustry() {
        return this.record?.Industry;
    }

    get myRating() {
        return this.record?.Rating;
    }

    get myWebsite() {
        return this.record?.Website;
    }
}

Since wired methods are called once the input parameters are setted, there is a moment in which the component is rendered but you don't have those data, so you have to render the related DOM elements conditionally.

HTML:

<template>
    <lightning-card title="My Account Record" icon-name="standard:account">
        <div class="slds-m-around_medium"  if:true={record}>
            <p>My name is: {myName}</p>
            <p>My industry is: {myIndustry}</p>
            <p>My rating is: {myRating}</p>
            <p>My website is: {myWebsite}</p>
        </div>
    </lightning-card>
</template>

You could've used getRecord from uiRecordApi in order to achieve the same result without writing apex code.

JS:

import { LightningElement, wire, api} from 'lwc';
import { getRecord, getFieldValue } from 'lightning/uiRecordApi';
import NAME_FIELD from '@salesforce/schema/Account.Name';
import INDUSTRY_FIELD from '@salesforce/schema/Account.Industry';
import RATING_FIELD from '@salesforce/schema/Account.Rating';
import WEBSITE_FIELD from '@salesforce/schema/Account.Website';

export default class FetchDataFromApex extends LightningElement {
    @api recordId;

    @wire(getRecord, {recordId: '$recordId', fields: [NAME_FIELD, INDUSTRY_FIELD, RATING_FIELD, WEBSITE_FIELD]})
    record;

    get myName() {
        return getFieldValue(this.record.data, NAME_FIELD);
    }

    get myIndustry() {
        return getFieldValue(this.record.data, INDUSTRY_FIELD);
    }

    get myRating() {
        return getFieldValue(this.record.data, RATING_FIELD);
    }

    get myWebsite() {
        return getFieldValue(this.record.data, WEBSITE_FIELD);
    }
}
4
  • Thank you so much. Very well explained. In the getter method return this.record?.Name; why is there a ?. Is this a typo? Commented May 16, 2021 at 13:38
  • 1
    @Krishnamurthy It isn't, ?. is the optional chaining operator (a.k.a. safe navigation operator). It saves null/undefined checks returning undefined if the reference is nullish instead of raising an error/exception. Apex has the safe navitation operator too.
    – RubenDG
    Commented May 16, 2021 at 13:54
  • Got it. I have one more doubt. Why data[0] and not data? Commented May 16, 2021 at 14:02
  • The apex method returns a List, so data will be an array. Since you're using the record's Id to filter the query, there will be only one element in that array, therefore its index will be 0. data[0] is the first element of the array, while just data is the array itself. If the apex method would have returned several Accounts, most likely in the wired function there have been a loop on data or a call to map method
    – RubenDG
    Commented May 16, 2021 at 14:17

You must log in to answer this question.

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