Hey Learner! Let’s look over a requirement to show the data on a new page in this blog. Similar to LMS, while pubsub facilitates communication by broadcasting, it doesn't inherently handle page navigation. Stay tuned to get more details on the implementation. Here we will be using NavigationMixing to pass data to the unrelated LWC component and pass the data in the encodedDefinition using Javascript and the btoa function to convert binary to ASCII. It is suitable when you want to trigger navigation events to standard or custom pages within the Salesforce app. The idea here is to show the related list of a child (Show few object tiles on the same page), and on clicking on the View All button, we will be redirected to an unrelated LWC component i.e, showChildRelatedListInNewPage using encodedDefinition by btoa function in js. Before the implementation, have a look at the logic and functionalities we are going to develop:
Create a parent component card to show the related campaignMembers on the lead page.
Each tile will show the child CampaignMember record having:
Link to the respective record detail page.
Details of the record.
The parent component will have a viewAll button, on click of which we will be passing the attributes to another LWC component using navigationMixing.
So, let us begin with the code implementation.
Prerequisite: Create the following custom label:
Name | Value |
VIEW_ALL | View All |
1. Create an Apex wrapper class - CampaignMemberWrapper
This class aims to wrap the data for the LWC component.
public with sharing class CampaignMemberWrapper {
public CampaignMember campaignMember;
public CampaignMemberWrapper(CampaignMember CampaignMember) {
this.campaignMember = campaignMember;
}
}
2. Create an Apex Domain class - CampaignMemberDomain
public class CampaignMemberDomain {
/**
* This method aims to fetch the related campaignMember
* @param leadId
*/
public static List<CampaignMember> getCampaignMemberByLeadId(String leadId) {
return [
SELECT
Campaign.Id,
Campaign.Name,
Campaign.IsActive,
Campaign.Status,
Campaign.Type,
Campaign.CreatedDate
FROM
CampaignMember
WHERE
leadId =: leadId
LIMIT 999
];
}
}
3. Create an Apex Processor class - CampaignMemberProcessor
This class aims to Process the data from the respective domain class to prepare the payload format in the LWC.
public with sharing class CampaignMemberProcessor {
/**
* This method aims to process the related campaignMember
* @param leadId
*/
public static List<CampaignMember> getCampaignMembers(String leadId) {
List<CampaignMember> processedData = new List<CampaignMember>();
for(CampaignMember campaignMember : CampaignMemberDomain.getCampaignMemberByLeadId(leadId)) {
CampaignMemberWrapper camp = new CampaignMemberWrapper(campaignMember);
processedData.add(camp.CampaignMember);
}
return processedData;
}
/**
* This method aims to get the Object fields dynamically from the filedset on the object
* @param : childApiName - Api name of the child to be queried
* @param : parentObjectId - parentObjectId
* @param : parentObjectName - parentObjectName
*/
public static List<sObject> childRecordDetailsQueryHelper(
String childApiName,
String parentObjectId,
String parentObjectName
) {
list<sobject> result = new list<sobject>();
try {
//Query the records to display in lead related list
if(childApiName == 'CampaignMember' && parentObjectName == 'Lead') {
result = getCampaignMembers(parentObjectId);
}else {
result = null;
throw new AuraHandledException(System.Label.VIEW_ALL);
}
}catch(Exception e) {
throw new AuraHandledException(e.getMessage());
}
return result;
}
}
4. Create an Apex Controller class - ChildObjectsController
This class aims to serve as the controller class for the LWC component to fetch the child data.
public with sharing class ChildObjectsController {
/**
* This method aims to make payload in json format respective to the API name provided in LWC
* @param : childApiNames - list of API name of the child to be queried
* @param : parentObjectId - parentObjectId
* @return : parentObjectName - parentObjectName
*/
@AuraEnabled(cacheable=true)
public static Map<String, List<sObject>> getChildRecordDetails(
list<String> childApiNames,
String parentObjectId,
String parentObjectName
) {
Map<String, List<sObject>> childApiAndLists = new Map<String, List<sObject>>();
childApiAndLists.put(
'CampaignMember',
CampaignMemberProcessor.childRecordDetailsQueryHelper('CampaignMember', parentObjectId, parentObjectName)
);
return childApiAndLists;
}
}
5. Create an LWC component: childLinkComp
This will serve as the child component so as to display a singular child object record. Here we will also be configuring tile for the tile view in the parent page and tabular view for the view all page.
childLinkComp.html
<template>
<!-- This component is made to handle the display of each record passed by the component -->
<article class="slds-tile slds-tile_board">
<div>
<!-- If the component is being displayed on the parent page we will show it as a tile by using flag showTile -->
<template if:true={showtile}>
<div class="demo-only">
<ul class="slds-has-dividers_around-space">
<li class="slds-item list">
<article class="slds-tile slds-tile_board">
<div class="slds-tile__detail">
<table>
<thead>
<tr>
<!-- Show the link of each record in their respective name to redirect to the respective record page-->
<td>
<a href={url} target="_blank">{currentchildobject.Name}</a>
</td>
</tr>
</thead>
<tbody>
<!-- Iterate through the key-value pair to get of the object to display the records -->
<template for:each={objectProperties} for:item="property">
<tr key={property.key}>
<td key={property.key}>
{property.key} : {property.value}
</td>
</tr>
</template>
</tbody>
</table>
</div>
</article>
</li>
</ul>
</div>
</template>
<!-- If showTile is false(implies the component is being shown in the new page), we will be using the tabular format to show the record in list view -->
<template if:false={showtile}>
<table class="slds-table slds-table_cell-buffer slds-no-row-hover slds-table_bordered slds-table_fixed-layout">
<tbody>
<tr class="slds-line-height_res" key={currentchildobject.key}>
<template for:each={objectProperties} for:item="property">
<td class="" scope="col" key={property.key}>
{property.value}
</td>
</template>
</tr>
</tbody>
</table>
</template>
</div>
</article>
</template>
childLinkComp.js
import { LightningElement, API } from 'lwc';
export default class ChildLinkComp extends LightningElement {
@api currentchildobject;
@api showtile;
get url() {
return (
window.location.origin + "/"+ this.currentchildobject.Id
);
}
get objectProperties() {
return (Object.entries(this.currentchildobject).map(([key, value])=>({key, value})));
}
}
childLinkComp.css
.list{
margin-bottom:10px;
margin-left:17px;
}
childLinkComp.js-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>58.0</apiVersion>
<isExposed>false</isExposed>
</LightningComponentBundle>
5. Create an LWC component: showChildRelatedListInNewPage
This will serve the logic to display the child records upon the viewAll button click by getting the attributes set via @api by the parentRelatedList LWC component.
The attributes captured will be further passed on to the childLinkComp LWC component to display the respective format.
showChildRelatedListInNewPage.html
<template>
<lightning-card title="Campaign History" key={isChildApiFound}>
<div class="header">
<p>
<button class="refresh-button" onclick={handleRefresh}>
<i class="glyphicon glyphicon-refresh fa fa-refresh"></i>
</button>
</p>
</div>
<template lwc:if={isChildApiFound}>
<table class="slds-table slds-table_cell-buffer slds-no-row-hover slds-table_bordered slds-table_fixed-layout">
<thead>
<tr class="slds-line-height_reset">
<template for:each={labels} for:item="label">
<th scope="col" key={label.key}>
<b>{label.key}</b>
</th>
</template>
</tr>
</thead>
</table>
<template for:each={relatedlists} for:item="childObj">
<table key={childObj.Id}>
<tbody>
<tr key={childObj.Id}>
<template lwc:if={isCampaign}>
<td>
<c-child-link-comp currentchildobject={childObj} showtile={showTile}></c-child-link-comp>
</td>
</template>
</tr>
</tbody>
</table>
</template>
</template>
</lightning-card>
</template>
showChildRelatedListInNewPage.js
import { LightningElement, api, track } from 'lwc';
import ERROR from "@salesforce/label/c.ERROR";
export default class ShowChildRelatedListInNewPage extends LightningElement{
@api relatedlists;
@api objNaming;
showTile = false;
labels;
isChildApiFound;
isCampaign = false;
childSize;
connectedCallback() {
if(this.relatedlists){
//lead- campaign member logic
if(this.objNaming == 'CampaignMember'){
this.relatedlists = this.relatedlists.CampaignMember.map(item => item.Campaign);
this.childSize = this.relatedlists.length;
this.isCampaign = true;
this.labels = (Object.entries(this.relatedlists[0]).map(([key,value])=>({ key, value })));
}
this.isChildApiFound = true;
}else{
alert(ERROR);
}
}
handleRefresh(event) {
location.reload();
}
}
showChildRelatedListInNewPage.css
.refresh-button{
margin-left: 10px;
}
.header{
margin-right:20px;
margin-bottom:5px;
}
showChildRelatedListInNewPage.js-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>58.0</apiVersion>
<isExposed>false</isExposed>
</LightningComponentBundle>
6. Create an LWC component - parentRelatedList This is the main component made to display the related list and pass the attributes via navigationMixing, also Please make sure that this is dragged in the Lead record page only as it has been created for the Lead record Page display only.
parentRelatedList.html
<template>
<article class="slds-card slds-card_boundary headerBottomBorder forceRelatedListCardDesktop">
<lightning-card class="slds-grid slds-page-header forceRelatedListCardHeader" title="Campaign History" key={camp}>
<template lwc:if={isChildApiFound}>
<template for:each={displayinSamePage} for:item="currentObject">
<table key={currentObject.Id}>
<tbody>
<tr key={currentObject.Id}>
<td class="tile_view">
<c-child-link-comp currentchildobject={currentObject} objapi="campaignmember" fieldlabel={labelNames} showtile={showtile}></c-child-link-comp>
</td>
</tr>
</tbody>
</table>
</template>
</template>
<footer class="slds-card__footer">
<button onclick={navigateToCampaignComponent}>{label.VIEW_ALL}</button>
</footer>
</lightning-card>
</article>
</template>
parentRelatedList.js
import { LightningElement, wire, track, api } from 'lwc';
import getChildObjects from '@salesforce/apex/ChildObjectsController.getChildRecordDetails';
import { NavigationMixin } from 'lightning/navigation';
import VIEW_ALL from "@salesforce/label/c.VIEW_ALL";
export default class parentRelatedList extends NavigationMixin(LightningElement) {
@api recordId;
@api objectApiName;
@track childApiAndLists;
@track displayinSamePage=[];
@track childRecords=[];
error;
isChildApiFound = false;
relatedlistsize = 2;
currentViewObj;
showtile = true;
label = {
VIEW_ALL
}
connectedCallback() {
this.relatedListDetails();
}
relatedListDetails() {
getChildObjects({
childApiNames : ['CampaignMember'],
parentObjectId : this.recordId,
parentObjectName : this.objectApiName
}).then((result) => {
this.childApiAndLists = result;
this.childRecords = result;
if (this.childApiAndLists){
this.isChildApiFound = true;
}
//Array to display in frontend recor page
this.displayinSamePage = this.childApiAndLists.CampaignMember.map(item => item.Campaign);
let campaignsToFrontEnd =[];
for(let index = 0; index < this.relatedlistsize; index++) {
if(this.displayinSamePage[index]){
campaignsToFrontEnd.push(this.displayinSamePage[index])
};
}
this.displayinSamePage = campaignsToFrontEnd;
this.error = undefined;
})
.catch((error) => {
this.error = error;
this.childApiAndLists = undefined;
});
}
navigateToCampaignComponent() {
this.currentViewObj = 'CampaignMember';
this.navigateToComponent();
}
navigateToComponent() {
let cmpDef = {
componentDef: "c:ShowChildRelatedListInNewPage",
attributes : {
relatedlists : this.childRecords,
objNaming : this.currentViewObj
}
};
let encodedDef = btoa(JSON.stringify(cmpDef));
this[NavigationMixin.Navigate]({
type: "standard__webPage",
attributes: {
url: "/one/one.app#" + encodedDef
}
});
}
}
parentRelatedList.css
.tile_view{
width: 342px;
padding-right: 19px
}
parentRelatedList.js-meta.xml
<?xml version="1.0"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>57.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__RecordPage</target>
</targets>
</LightningComponentBundle>
Some key points here:
The parentRelatedList component is currently configured to be available for the lead record page only.
You can configure how many child records to display by setting the relatedlistsize per your concern.
So let’s finally drag and drop the component to see the results.
Open any lead record page.
Click on the gear icon (Settings) | Edit Page.
Drag drop parentRelatedList LWC component to the desired place on the layout and save and activate.
Here are the results:
Click on viewAll.
You can also refresh the page by clicking on the refresh icon.
Conclusion
In conclusion, this blog post introduced a creative solution for passing data to unrelated Lightning Web Components (LWC) using Navigation Mixing. By utilizing Apex classes, custom labels, and LWC components, the author demonstrated how to display related records and navigate to a new page to view all records, enhancing the user experience and functionality.
If you'd like to see the code and resources used in this project, you can access the repository on GitHub.To access the AVENOIRBLOGS repository, click here. Feel free to explore the code and use it as a reference for your projects.
Happy Coding! You can leave a comment to help me understand how the blog helped you. If you need further assistance, please contact us. You can click "Reach Us" on the website and share the issue with me.
Blog Credit:
D. Dewangan
Salesforce Developer
Avenoir Technologies Pvt. Ltd.
Reach us: team@avenoir.ai
Are you in need of Salesforce Developers?
Reach Us Now!
Comments