3

I recently started to work with LWC, I want to bind a certain field from the controller and use it in my component

My LWC is on the Case object, I have a controller which returns an array of related email messages. What I want to do is to use the 'Incoming' field on my component:

import { LightningElement, api, track, wire } from 'lwc';
import getAllEmailsForRecord from '@salesforce/apex/getRelatedEmails.getAllEmailsForRecord'; 

export default class ShowRelatedRecords extends LightningElement {
    @api recordId;
    @track record;
    @track error;

    @wire(getAllEmailsForRecord, { caseId: '$recordId' }) 
    emails; 

    get incoming() {
        return this.emails.data.fields.Incoming.value;
    }
}

Html:

<template for:each={emails.data} for:item="email">
<lightning-layout-item key={email.Id} size="12">
<div  class="slds-p-around_x-small" >
   <lightning-badge label={incoming}></lightning-badge>
</div>
....

Controller:

public without sharing class getRelatedEmails {
@AuraEnabled(Cacheable=true)
    public static EmailMessage[] getAllEmailsForRecord(Id caseId){
        return [SELECT Id,TextBody, IsExternallyVisible ,Subject,FromAddress,ToAddress,Incoming FROM EmailMessage WHERE ParentId = : caseId];
    }  
}

The result is that the LWC does not load and when I open the chrome debugger I see the following error:

Error: Uncaught (in promise) TypeError: Cannot read property 'Incoming' of undefined at i.get incoming [as incoming]

5
  • 2
    Is Incoming a custom field? If so, I would expect it to be Incoming__c in the JSON Otherwise, I often try using debugger or JSON.Stringify to see the structure of the response May 7, 2019 at 15:35
  • It's a standard field of EmailMessage
    – Json
    May 7, 2019 at 17:07
  • @Json Have you tried just printing this.emails.data? What does it return?
    – Jayant Das
    May 7, 2019 at 17:52
  • Note that if I remove the {incoming} line then everything works, I can see my list of emails with all the fields . so 'this.email.data' is not empty.
    – Json
    May 7, 2019 at 17:58
  • have you checked if the user using this component has access to the email object as well as the incoming field. lds obeys fls.
    – joshii
    May 9, 2019 at 20:41

5 Answers 5

5
+50

You are in a loop <template for:each={emails.data} for:item="email"> which means below is how you need to access data for an instance of the record in the data array. Here email is the indidual record attribute which you have declared through for:item="email

 <lightning-badge label={email.Incoming}></lightning-badge>

You are trying to run an expression function on a list of records this.emails.data.fields.Incoming.value but data your data is an array so you need to access specific node of array inside the template if

Solution 2:

Create a child component and put all the contents inside for loop there

Child Component markup:

<template>
    <p>{email.TextBody}</p>
    <div  class="slds-p-around_x-small" >
        <lightning-badge label={incoming}></lightning-badge>
     </div>
</template>

JS File:

import { LightningElement,api} from 'lwc';

    export default class EmailRecord extends LightningElement {
        @api email;
        get incoming() {
            return this.email.Incoming;
        }   

    }

In the parent component where you are getting data change the markup(html template like this) where c-email-record is your child component

<template>

<template for:each={emails.data} for:item="email">
    <lightning-layout-item key={email.Id} size="12">
    <c-email-record email={email}></c-email-record>
    </lightning-layout-item>
</template>    
</template>

within this child component js you can do whatever manipulation of data you want to and then show the UI accordingly

5
  • I want to access the Incoming field for each Email Message and add some custom logic, so I'm afraid just printing the {email.Incoming} for each record is not helpful. I need to be able to get the field in JS, add some logic and then use it in the html page. To be more specific, if the value of EmailMessage.Incoming is true I want to show 'Incoming' and if false 'Outgoing'
    – Json
    May 9, 2019 at 20:33
  • @Json, should be fine just put everything inside the loop as a seperate component and write the expression function there it will work the way you want. Just access the email attribute and do whatever you want to do
    – RedDevil
    May 9, 2019 at 20:35
  • thanks for your help, can you please edit your answer and provide a few pointers/steps on how to do it?
    – Json
    May 9, 2019 at 20:37
  • @Json,added the solution.check solution 2
    – RedDevil
    May 9, 2019 at 20:51
  • looks like this is it, thanks again!
    – Json
    May 9, 2019 at 21:08
0

A record isn't loaded immediately; you need to make sure there's a value first:

get incoming() {
    return this.emails && this.emails.data && this.emails.data.fields.Incoming.value;
}

This is true for any time you need to get data from the server.

1
  • Hi @sfdcfox, I tried your suggestion but same results, any thoughts?
    – Json
    May 7, 2019 at 17:15
0

Alternatively to @sfdcfox's answer, wrap truthiness for the wired variable for any dependent calculations:

<template if:true={emails.data}>
  <lightning-badge label={emails.data.fields.Incoming.value}></lightning-badge>
</template>

Then you can omit the getter completely and move the verbosity to template.

4
  • Hi, can I use if:true in a div ?
    – Json
    May 7, 2019 at 17:51
  • @Json yes you can
    – tsalb
    May 7, 2019 at 19:00
  • still getting an error, if I remove the {incoming} then . the list of emails loads correctly.
    – Json
    May 8, 2019 at 8:12
  • Hi @tsalb, any ideas?
    – Json
    May 9, 2019 at 13:58
0

I think in what you have tried to do, you should have just remove fields and select some record, for example, the first one and in such case you would be able not to have an error and access incoming property on the first email message records assuming that you have at least one such record.

import { LightningElement, api, track, wire } from 'lwc';
import getAllEmailsForRecord from '@salesforce/apex/getRelatedEmails.getAllEmailsForRecord'; 

export default class ShowRelatedRecords extends LightningElement {
    @api recordId;
    @track record;
    @track error;

    @wire(getAllEmailsForRecord, { caseId: '$recordId' }) 
    emails; 

    get incoming() {
        return this.emails.data[0].Incoming;
    }
}
0

Another option is just to use wrapper object list, in such case you don't need additional component to manipulate the data shown

import { LightningElement, api, track, wire } from 'lwc';
import getAllEmailsForRecord from '@salesforce/apex/getRelatedEmails.getAllEmailsForRecord'; 

export default class ShowRelatedRecords extends LightningElement {
    @api recordId;
    @track record;
    @track error;

    @wire(getAllEmailsForRecord, { caseId: '$recordId' }) 
    emails; 

    @track wrappers;
    connectedCallback() {
        getAllEmailsForRecord({ caseId: this.recordId })
        .then(result=>{
            this.wrappers = result.map(function(x){
                return {IncomingOrOutgoingText: x.Incoming ? 'Incoming' : 'Outgoing', origin:x};
            })
        }).catch(error => {
            this.error = error;
        });
    }
}

Html

<template>    
    <lightning-layout>
        <template for:each={wrappers} for:item="emailWrapper">
            <lightning-layout-item key={emailWrapper.origin.Id}>
                <div  class="slds-p-around_x-small" >
                    <lightning-badge label={emailWrapper.IncomingOrOutgoingText}></lightning-badge>
                </div>
            </lightning-layout-item>
        </template>
    </lightning-layout>

</template>

enter image description here

You must log in to answer this question.

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