Data Tables in LWC with related fields
By now you would have noticed that displaying data from related objets into a single data table can be a little bit tricky in Lightning Web Component.
Sep 18, 2019
• 2 min read
Data Tables in LWC gets painful to work with when you want to display the data from related objets into a single data table .
Data tables in LWC showing data from related objects The bottle neck that we face here is when we get the data back, that’s going to be in nested json format.
There are a couple of things on which we need to work on to get the Data Tables in LWC to work as expected.
The response that we get from Apex method should resemble the json we declared for the columns in data table. Something like this .. const columns = [
{ label: 'Label', fieldName: 'Name' },
{ label: 'Website', fieldName: 'LeadSource' },
{ label: 'Phone', fieldName: 'Phone', type: 'phone' },
{ label: 'Account Name', fieldName: 'Account.Name'},
{ label: 'Account Industry', fieldName: 'Account.Industry'}
];
The response we get will be similar to the format shown below and we need to flatten it to resemble the json declared for the columns. So the below json response should be flattened to .. {
"Id": "0032v00002lLzgQAAS",
"Name": "Rose Rose",
"Phone": "(512) 757-6000",
"LeadSource": "Trade Show",
"AccountId": "0012v00002M0O2CAAV",
"Account": {
"Name": "Edge Communications",
"Industry": "Electronics",
"Id": "0012v00002M0O2CAAV"
}
}
Typical response when we invoke a SOQL query
something like this ..
{
"Id": "0032v00002lLzgQAAS",
"Name": "Rose Rose",
"Phone": "(512) 757-6000",
"LeadSource": "Trade Show",
"AccountId": "0012v00002M0O2CAAV",
"Account.Name": "Edge Communications",
"Account.Industry": "Electronics",
"Account.Id": "0012v00002M0O2CAAV"
}
The response we received has to be flattened like this
Okay! Let's get started.
This is how my template file is going to look like.
<template>
<div style="height: 500px;">
<lightning-datatable
key-field="id"
data={allContacts}
columns={columns}>
</lightning-datatable>
</div>
</template>
exploreCustomDataTable.html
Then comes the js file.
import { LightningElement, wire, track } from 'lwc';
import getContacts from '@salesforce/apex/ExploreCustomContactController.getContacts';
const columns = [
{ label: 'Label', fieldName: 'Name' },
{ label: 'Website', fieldName: 'LeadSource' },
{ label: 'Phone', fieldName: 'Phone', type: 'phone' },
{ label: 'Account Name', fieldName: 'Account.Name'},
{ label: 'Account Industry', fieldName: 'Account.Industry'}
];
export default class ExploreCustomDataTable extends LightningElement {
@track allContacts = [];
@track columns = columns;
//wiring an apex method to a function
@wire(getContacts)
wiredContacts({ error, data }) {
if(data) {
//this is the final array into which the flattened response will be pushed.
let contactsArray = [];
for (let row of data) {
// this const stroes a single flattened row.
const flattenedRow = {}
// get keys of a single row — Name, Phone, LeadSource and etc
let rowKeys = Object.keys(row);
//iterate
rowKeys.forEach((rowKey) => {
//get the value of each key of a single row. John, 999-999-999, Web and etc
const singleNodeValue = row[rowKey];
//check if the value is a node(object) or a string
if(singleNodeValue.constructor === Object){
//if it's an object flatten it
this._flatten(singleNodeValue, flattenedRow, rowKey)
}else{
//if it’s a normal string push it to the flattenedRow array
flattenedRow[rowKey] = singleNodeValue;
}
});
//push all the flattened rows to the final array
contactsArray.push(flattenedRow);
}
//assign the array to an array that's used in the template file
this.allContacts = contactsArray;
} else if (error) {
this.error = error;
}
}
/* create keys in the format of Account.Id, Account.Rating, Account.Industry and etc
we can avoid using this function by reusing the above function.
To understand in easily I used a separate function
Feel free to refactor it */
_flatten = (nodeValue, flattenedRow, nodeName) => {
let rowKeys = Object.keys(nodeValue);
rowKeys.forEach((key) => {
let finalKey = nodeName + '.'+ key;
flattenedRow[finalKey] = nodeValue[key];
})
}
}
exploreCustomDataTable.js
It's not that we can only show data from two related objects. We can also show data from multiple objects that are in a relationship, as long as the flattened JSON response resembles the JSON we used in declaring the columns.
Liked the post? Let me know what you think of it.