Sample Code:
Apex Class:
public class RelatedListController {
@AuraEnabled
public static RelatedListResult fetchRecs( String recId, String sObjName, String parentFldNam, String strCriteria ) {
String strTitle = ' (';
List < sObject > listsObjects = new List < sObject >();
RelatedListResult obj = new RelatedListResult();
String strSOQL = 'SELECT Id FROM ' + sObjName + ' WHERE ' + parentFldNam + ' = '' + recid + ''';
if ( String.isNotBlank( strCriteria ) )
strSOQL += ' ' + strCriteria;
strSOQL += ' LIMIT 4';
listsObjects = Database.query( strSOQL );
Integer intCount = listsObjects.size();
if ( intCount > 3 ) {
List < sObject > tempListsObjects = new List < sObject >();
for ( Integer i = 0; i <3; i++ )
tempListsObjects.add( listsObjects.get( i ) );
obj.listsObject = tempListsObjects;
strTitle += '3+';
} else {
obj.listsObject = listsObjects;
strTitle += String.valueOf( intCount );
}
strTitle += ')';
obj.strTitle = strTitle;
return obj;
}
public class RelatedListResult {
@AuraEnabled
public String strTitle;
@AuraEnabled
public List < sObject > listsObject;
}
}
Lightning Component:
<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId" access="global" controller="RelatedListController" >
<aura:attribute name="relatedListURL" type="String"/>
<aura:attribute name="title" type="String"/>
<aura:attribute name="criteria" type="String"/>
<aura:attribute name="parentFieldName" type="String"/>
<aura:attribute name="sobjectName" type="String"/>
<aura:attribute name="ObjectName" type="String"/>
<aura:attribute name="childRelName" type="String"/>
<aura:attribute name="iconName" type="String"/>
<aura:attribute name="field1" type="String"/>
<aura:attribute name="field2" type="String"/>
<aura:attribute name="field3" type="String"/>
<aura:attribute name="field4" type="String"/>
<aura:attribute name="listRecords" type="sObject[]"/>
<aura:handler name="init" value="{!this}" action="{!c.fetchRecords}"/>
<lightning:card iconName="{!v.iconName}">
<aura:set attribute="title">
<aura:if isTrue="{!not(empty(v.listRecords))}">
<lightning:button variant="base"
label="{!v.title}"
title="View All Action"
onclick="{! c.viewRelatedList }"/>
</aura:if>
</aura:set>
<p class="slds-p-horizontal_small">
<aura:iteration items="{!v.listRecords}" var="item">
<lightning:button variant="base"
label="{! 'View ' + v.ObjectName }"
title="View"
onclick="{! c.viewRecord }"
value="{!item.Id}"/>
<lightning:recordViewForm recordId="{!item.Id}" objectApiName="{!v.sobjectName}">
<div class="slds-grid">
<div class="slds-col slds-size_1-of-2">
<lightning:outputField fieldName="{!v.field1}" />
</div>
<div class="slds-col slds-size_1-of-2">
<lightning:outputField fieldName="{!v.field2}" />
</div>
</div>
<div class="slds-grid">
<div class="slds-col slds-size_1-of-2">
<lightning:outputField fieldName="{!v.field3}" />
</div>
<div class="slds-col slds-size_1-of-2">
<lightning:outputField fieldName="{!v.field4}" />
</div>
</div>
</lightning:recordViewForm><br/><br/>
</aura:iteration>
</p>
<aura:set attribute="footer">
<aura:if isTrue="{!not(empty(v.listRecords))}">
<lightning:button variant="base"
label="View All"
title="View All Action"
onclick="{! c.viewRelatedList }"/>
</aura:if>
</aura:set>
</lightning:card>
</aura:component>
Lightning Component Controller:
({
fetchRecords : function(component, event, helper) {
var temObjName = component.get( "v.sobjectName" );
component.set( "v.ObjectName", temObjName.replace( "__c", "" ).replace( "_", " " ) );
var action = component.get( "c.fetchRecs" );
action.setParams({
recId: component.get( "v.recordId" ),
sObjName: temObjName,
parentFldNam: component.get( "v.parentFieldName" ),
strCriteria: component.get( "v.criteria" )
});
action.setCallback(this, function(response) {
var state = response.getState();
if ( state === "SUCCESS" ) {
var tempTitle = component.get( "v.title" );
component.set( "v.listRecords", response.getReturnValue().listsObject );
component.set( "v.title", tempTitle + response.getReturnValue().strTitle );
}
});
$A.enqueueAction(action);
},
viewRelatedList: function (component, event, helper) {
var navEvt = $A.get("e.force:navigateToRelatedList");
navEvt.setParams({
"relatedListId": component.get( "v.childRelName" ),
"parentRecordId": component.get( "v.recordId" )
});
navEvt.fire();
},
viewRecord: function (component, event, helper) {
var navEvt = $A.get("e.force:navigateToSObject");
var recId = event.getSource().get( "v.value" )
navEvt.setParams({
"recordId": recId
});
navEvt.fire();
}
})
Lightning Component Design:
<design:component>
<design:attribute name="title" label="Title" required="true"/>
<design:attribute name="parentFieldName" label="Parent Field API Name" required="true"/>
<design:attribute name="sobjectName" label="Object API Name" required="true"/>
<design:attribute name="criteria" label="Additonal Criteria"/>
<design:attribute name="childRelName" label="Child Relationship Name" required="true"/>
<design:attribute name="iconName" label="Icon Name" required="true"/>
<design:attribute name="field1" label="Field 1" required="true"/>
<design:attribute name="field2" label="Field 2" required="true"/>
<design:attribute name="field3" label="Field 3" required="true"/>
<design:attribute name="field4" label="Field 4" required="true"/>
</design:component>
App Builder configuration:

Output:
