Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save vermadhirendra28/7cdec6fa55aaa194206038ab762738f2 to your computer and use it in GitHub Desktop.
Save vermadhirendra28/7cdec6fa55aaa194206038ab762738f2 to your computer and use it in GitHub Desktop.
Generic Lightning Datatable with New and modify Option
/**
* Desc: A apex class which can be used to create a dynamic lightning datatable only by passing the object name and fields name
* that we need to display as column for the Datatable
**/
public class CreateDynamicDatatable {
/**
* Wrapper that will be used by the lightning datatable as columns
*/
public with sharing class DynamicDataTableColumn {
@AuraEnabled public String type{get; set;}
@AuraEnabled public String fieldName{get; set;}
@AuraEnabled public String label{get; set;}
public DynamicDataTableColumn(String type, String fieldName, String label) {
this.type = type;
this.fieldName = fieldName;
this.label = label;
}
}
/**
* A wrapper that represents the collection of column, object name and the list of records data that need
* to display in the lightning table
**/
public with sharing class DynamicDataTable{
public String strObjectlabel{get;set;}
public String strObjectApiName{get;set;}
public list<SObject> listObjectData{get;set;}
public List<DynamicDataTableColumn> listDataColumn{get;set;}
public DynamicDataTable(String p_strObjectlabel,String p_strObjectApiName,
list<SObject> p_listObjectData,List<DynamicDataTableColumn> p_listDataColumn){
this.strObjectlabel = p_strObjectlabel;
this.strObjectApiName = p_strObjectApiName;
this.listObjectData = p_listObjectData;
this.listDataColumn = p_listDataColumn;
}
}
/***
* Desc: a method which recieves the object name along with its fields api
* and returns the label for that object and its provided fields
**/
public static map<String,List<DynamicDataTableColumn>> fetchlabels(map<string,string> p_mapObjectWithField){
map<String,String> mapDataWithlabel = new map<String,String>();
map<String,List<DynamicDataTableColumn>> mapObjectWithColumns = new map<String,List<DynamicDataTableColumn>>();
for(String strObjectName : p_mapObjectWithField.keyset()){
Map<String, Schema.SObjectType> global_describe = Schema.getGlobalDescribe();
Map<String, Schema.SObjectField> object_fields_map = global_describe.get(strObjectName).getDescribe().fields.getMap();
List<DynamicDataTableColumn> columns = new List<DynamicDataTableColumn>();
for(String strFieldApiLabel :p_mapObjectWithField.get(strObjectName).split(',')){
system.debug('datatypevlaue ***'+object_fields_map.get(strFieldApiLabel).getDescribe().getType());
String fieldLabel = object_fields_map.get(strFieldApiLabel).getDescribe().getLabel();
String fieldType = String.valueOf(object_fields_map.get(strFieldApiLabel).getDescribe().getType());
DynamicDataTableColumn newCell = new DynamicDataTableColumn(
convertToLightningDataType(fieldType),
String.escapeSingleQuotes(strFieldApiLabel),
fieldLabel);
columns.add(newCell);
}
mapObjectWithColumns.put(strObjectName,columns);
}
system.debug('columns***'+mapObjectWithColumns);
return mapObjectWithColumns;
}
/**
* Desc: A method that fetch all the data that needs to be displayed on the lightning datatable
**/
@AuraEnabled
public static map<String,Object> getTableData(String strObjectName,
String strApiFields,
String strPageRecordSize){
map<String,String> mapObjectWithField = new map<String,String>();
map<String,Object> mapData = new map<String,Object>();
system.debug('strObjectName***'+strObjectName);
system.debug('listGridcolumn***'+ strApiFields);
mapObjectWithField.put(strObjectName,strApiFields);
map<String,List<DynamicDataTableColumn>> mapObjectWithColumns = fetchlabels(mapObjectWithField);
system.debug('mapObjectWithColumns***'+mapObjectWithColumns);
List<DynamicDataTableColumn> listSelectedGridcol = mapObjectWithColumns.get(strObjectName);
list<SObject> listObject = new List<SObject>();
String strQuery = 'Select Id';
for(DynamicDataTableColumn objCell: mapObjectWithColumns.get(strObjectName)){
strQuery = strQuery +','+ objCell.fieldName;
}
strQuery = strQuery + ' From ' +strObjectName +' limit ' +strPageRecordSize ;
system.debug('strQuery***'+strQuery);
for(SObject o : Database.query(strQuery)){
listObject.add(o);
}
system.debug(listObject);
map<String,String> mapObjectWithLabel = fetchObjectRelatedLabel(mapObjectWithField);
DynamicDataTable objNewData = new DynamicDataTable(mapObjectWithLabel.get(strObjectName),
strObjectName,
listObject,
listSelectedGridcol);
mapData.put('DataFetched',JSON.serialize(objNewData));
return mapData;
}
/**
* Desc: A method to fetch the object Label from the api name passed as a parameter to the method
**/
public static map<String,String> fetchObjectRelatedLabel(map<String,String> mapSobjectApiWithFields){
map<String,String> mapObjectApiWithLabel = new map<String,String>();
Map <String, Schema.SObjectType> schemaMap = Schema.getGlobalDescribe();
for(String objApiName : mapSobjectApiWithFields.keySet()){
String strObjectLabel = String.valueOf(schemaMap.get(objApiName).getDescribe().getLabel());
mapObjectApiWithLabel.put(objApiName,strObjectLabel);
}
return mapObjectApiWithLabel;
}
/**
* Desc: A method to used to convert the apex datatype to lightning data type
**/
public static String convertToLightningDataType(String apexFieldDataType) {
String lightningDataType = 'text'; // default
apexFieldDataType = apexFieldDataType.toLowerCase();
Map<String, Set<String>> lightningToApexDataTypeMap = new Map<String, Set<String>>{
'text' => new Set<String>{'address', 'id', 'phone', 'email', 'string', 'textarea'},
'date' => new Set<String>{'date', 'datetime'},
'number' => new Set<String>{'double', 'integer'},
'percent' => new Set<String>{'percent'},
'currency' => new Set<String>{'currency'},
'url' => new Set<String>{'url'}
};
for (String type : lightningToApexDataTypeMap.keySet()) {
if (lightningToApexDataTypeMap.get(type).contains(apexFieldDataType)) {
lightningDataType = type;
break;
}
}
return lightningDataType;
}
}
<!-- lighning component for dynamic data table with new an modify option ---->
<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes,force:lightningQuickAction" access="global"
controller="CreateDynamicDatatable">
<aura:attribute name="strObjectApiName" type="String" default="Account" access="global"/>
<aura:attribute name="fields" type="String"
default="Name" access="global"/>
<aura:attribute name="fetchedSelectedRecords" type="Object" access="global"/>
<aura:attribute name="selectedObjectRecList" type="list" />
<aura:attribute name="noOfRecordsOnPage" type="integer" default="100" access="global"/>
<aura:attribute name="displayTable" type="boolean" default="true" />
<aura:attribute name="Spinner" type="boolean" default="false"/>
<aura:attribute name="displayCreateModalForm" type="boolean" default="false"/>
<aura:attribute name="displayModifyModal" type="boolean" default="false"/>
<aura:attribute name="objFields" type="String[]"></aura:attribute>
<aura:attribute name="modifiedRecordId" type="String" default=""/>
<aura:attribute name="modifiedbuttondisabled" type="Boolean" default="false" />
<aura:attribute name="modifylabel" type="string" default="Modify" access="global"/>
<aura:attribute name="isEditable" type="boolean" default="true" access="global" />
<lightning:notificationsLibrary aura:id="notifLib"/>
<!--aura:attrbute name="strObjectLabel" type="String" access="global"/ -->
<!--handler method -->
<aura:handler event="aura:waiting" action="{!c.showSpinner}"/>
<aura:handler event="aura:doneWaiting" action="{!c.hideSpinner}"/>
<aura:handler name="init" value="{!this}" action="{!c.init}" />
<!-- Register events -->
<aura:registerEvent name="callPassDynamicSelectedRecEvt" type="c:passDynamicSelectedRec"/>
<div class="container">
<!--loading spinner start... style=Brand Medium (blue dots)-->
<aura:if isTrue="{!v.Spinner}">
<div aura:id="spinnerId" class="slds-spinner_container">
<div class="slds-spinner--brand slds-spinner slds-spinner--large slds-is-relative" role="alert">
<span class="slds-assistive-text">Loading</span>
<div class="slds-spinner__dot-a"></div>
<div class="slds-spinner__dot-b"></div>
</div>
</div>
</aura:if>
<aura:if isTrue="{!v.displayTable}">
<div class="slds-page-header">
<article class="slds-card">
<div class="slds-card__header slds-grid">
<header class="slds-media slds-media_center slds-has-flexi-truncate">
<div class="slds-media__figure">
<span class="slds-icon_container slds-icon-standard-account" title="{!v.fetchedSelectedRecords.strObjectlabel}">
<lightning:icon iconName="utility:custom1" size="medium"/>
<span class="slds-assistive-text">{!v.fetchedSelectedRecords.strObjectlabel}</span>
</span>
</div>
<div class="slds-media__body">
<h2 class="slds-card__header-title">
<a href="javascript:void(0);" class="slds-card__header-link slds-truncate" title="Accounts">
<span>{!v.fetchedSelectedRecords.strObjectlabel}</span>
</a>
</h2>
</div>
<div class="slds-no-flex">
<button class="slds-button slds-button_neutral" data-record="{!v.fetchedSelectedRecords.strObjectApiName}"
onclick="{!c.createNewRecord}"
data-label="New">New</button>
</div>
</header>
</div>
<div class="slds-card__body slds-card__body_inner">
<lightning:datatable data="{!v.fetchedSelectedRecords.listObjectData}"
columns="{!v.fetchedSelectedRecords.listDataColumn}"
keyField="Id"
onrowselection="{!c.handleSelect}"
onrowaction="{!c.modifySelectedRecord}"/>
</div>
</article>
<div style="padding-top:2%;text-align:center">
<button class="slds-button slds-button_brand" onclick="{!c.getSelectedRec}">
Get Seleced Records
</button>
</div>
</div>
</aura:if>
<!--modal popup to display the editable form for the selected record-->
<aura:if isTrue ="{!v.displayModifyModal}">
<div style="height:640px">
<section role="dialog" tabindex="-1" aria-labelledby="modal-heading-01" aria-modal="true"
aria-describedby="modal-content-id-1" class="slds-modal slds-fade-in-open">
<div class="slds-modal__container">
<header class="slds-modal__header">
<button class="slds-button slds-button_icon slds-modal__close slds-button_icon-inverse"
title="Close" onclick="{!c.closeModifyModal}">
<lightning:icon iconName="action:close" size="small"/>
<span class="slds-assistive-text">Close</span>
</button>
<h2 id="modal-heading-01" class="slds-text-heading_medium slds-hyphenate">
{!v.fetchedSelectedRecords.strObjectlabel}
</h2>
</header>
<div class="slds-modal__content slds-p-around_medium" id="modal-content-id-1">
<lightning:recordEditForm
onload="{!c.handleModifyLoad}"
onsubmit="{!c.handleModifySubmit}"
onsuccess="{!c.handleModifySuccess}"
recordId="{!v.modifiedRecordId}"
objectApiName="{!v.fetchedSelectedRecords.strObjectApiName}">
<!-- the messages component is for error messages -->
<lightning:messages />
<aura:iteration items="{!v.objFields}" var="fieldApiname">
<lightning:inputField fieldName="{!fieldApiname}" />
</aura:iteration>
<div class="slds-m-top_medium">
<lightning:button disabled="{!v.modifiedbuttondisabled}" variant="brand" type="submit" name="save" label="Save" />
</div>
</lightning:recordEditForm>
</div>
<footer class="slds-modal__footer">
</footer>
</div>
</section>
<div class="slds-backdrop slds-backdrop_open"></div>
</div>
</aura:if>
<!--end of modal popup for editable form -->
<!-- beginning of create record modal -->
<aura:if isTrue="{!v.displayCreateModalForm}">
<div style="height:640px">
<section role="dialog" tabindex="-1" aria-labelledby="modal-heading-01" aria-modal="true"
aria-describedby="modal-content-id-1" class="slds-modal slds-fade-in-open">
<div class="slds-modal__container">
<header class="slds-modal__header">
<button class="slds-button slds-button_icon slds-modal__close slds-button_icon-inverse"
title="Close" onclick="{!c.closeCreateFormModal}">
<lightning:icon iconName="action:close" size="small"/>
<span class="slds-assistive-text">Close</span>
</button>
<h2 id="modal-heading-01" class="slds-text-heading_medium slds-hyphenate">
{!v.fetchedSelectedRecords.strObjectlabel}
</h2>
</header>
<div class="slds-modal__content slds-p-around_medium" id="modal-content-id-3">
<lightning:recordForm
objectApiName="{!v.strObjectApiName}"
fields="{!v.objFields}"
onsuccess="{!c.handleSuccess}" />
</div>
<footer class="slds-modal__footer">
</footer>
</div>
</section>
<div class="slds-backdrop slds-backdrop_open"></div>
</div>
</aura:if>
<aura:if isTrue ="{!!displayTable}">
<div class="messagecontainer center fontsize">
</div>
</aura:if>
</div>
</aura:component>
<!--- end of lightning component -->
/**Begining of dynamicLDTWithNewAndModifyOptionController.js code **/
({
init : function(component, event, helper) {
helper.getTableData(component,event);
},
handleSelect:function(component,event,helper){
try{
helper.createSelectedReclist(component,event);
}catch(e){
console.error(e);
}
},
getSelectedRec: function(component,event,helper){
try{
helper.fetchSelectedRecordList(component,event);
}catch(e){
console.error(e);
}
},
createNewRecord: function(component,event,helper){
helper.displayRecordCreateForm(component,event);
},
closeCreateFormModal: function(component,event,helper){
component.set("v.displayCreateModalForm",false);
},
modifySelectedRecord : function(component,event,helper){
helper.displayModifyForm(component,event);
},
closeModifyModal : function(component,event,helper){
component.set("v.displayModifyModal",false);
},
handleModifyLoad: function(cmp, event, helper) {
},
handleModifySubmit: function(cmp, event, helper) {
cmp.set('v.modifiedbuttondisabled', true);
},
handleModifySuccess: function(component, event, helper) {
// errors are handled by lightning:inputField and lightning:nessages
// so this just hides the spinnet
component.set("v.displayModifyModal",false);
alert('record successfully modified');
},
closeCreateFormModal : function(component,event,helper){
component.set("v.displayModifyModal",false);
},
handleSuccess : function(component, event, helper) {
component.set("v.displayCreateModalForm",false);
var recId = event.getParam("id");
console.log(recId);
if(recId != undefined){
alert('record successfully inserted');
}else{
alert('some error occured during record insertion');
}
},
// this function automatic call by aura:waiting event
showSpinner: function(component, event, helper) {
// make Spinner attribute true for display loading spinner
component.set("v.Spinner", true);
},
// this function automatic call by aura:doneWaiting event
hideSpinner : function(component,event,helper){
// make Spinner attribute to false for hide loading spinner
component.set("v.Spinner", false);
}
})
/** end of dynamicLDTWithNewAndModifyOptionController.js code **/
/**
* Begining of dynamicLDTWithNewAndModifyOptionHelper.js code **
*/
({
getTableData : function(cmp,event) {
var limitRecordsize = cmp.get("v.noOfRecordsOnPage");
var execAction = cmp.get("c.getTableData");
execAction.setParams({
"strObjectName":cmp.get("v.strObjectApiName"),
"strApiFields" :cmp.get("v.fields"),
"strPageRecordSize":limitRecordsize
});
this.serverSideCall(cmp,execAction).then(
function(res) {
console.log(res);
var queriedResult = JSON.parse(res.DataFetched);
if(cmp.get("v.isEditable")){
queriedResult.listDataColumn.push({type: "button",
typeAttributes: {
label: cmp.get("v.modifylabel"),
name: cmp.get("v.strObjectApiName"),
title: cmp.get("v.modifylabel"),
disabled: false,
value: cmp.get("v.modifylabel"),
iconPosition: 'left'
}
});
}
if(queriedResult.listObjectData.length > 0){
cmp.set("v.fetchedSelectedRecords",queriedResult);
console.log('listObjectData***'+queriedResult.listObjectData);
/*Data.forEach(function assignModifyColumn(temp,index){
console.log('form column data'+temp);*/
//cmp.set("v.strObjectLabel",queriedResult.strObjectlabel);
}
}).catch(
function(error) {
console.log(error);
cmp.set("v.displayTable",false);
}
);
},
createSelectedReclist: function(component,event){
var selectedRows = event.getParam('selectedRows');
let listObjectRec = [] ;
if(selectedRows.length > 0){
for(var i = 0;i<selectedRows.length;i++){
listObjectRec.push(selectedRows[i].Id);
}
}
console.log('list of selectedrec ***'+listObjectRec);
component.set('v.selectedObjectRecList',listObjectRec);
},
/**
* A javascript method to pass the selected recordlist back to the parent component
**/
fetchSelectedRecordList: function(component,event){
var selectedReclist = component.get("v.selectedObjectRecList");
var cmpEvent = component.getEvent("callPassDynamicSelectedRecEvt");
cmpEvent.setParams({"selectedRecordId" : selectedReclist});
cmpEvent.fire();
},
/**
* a method to create the new record for the selected object
**/
displayRecordCreateForm: function(component,event){
var objectFields = component.get("v.fields");
var listSelectedObjectFields = objectFields.split(',');
component.set("v.objFields",listSelectedObjectFields);
component.set("v.displayCreateModalForm",true);
},
/**
* A method to modify the existing records
**/
displayModifyForm : function(component,event){
var recId = event.getParam('row').Id;
var actionObjectName = event.getParam('action').name;
console.log(actionObjectName);
console.log(recId);
var objectFields = component.get("v.fields");
var listSelectedObjectFields = objectFields.split(',');
component.set("v.objFields",listSelectedObjectFields);
component.set("v.modifiedRecordId",recId);
component.set("v.displayModifyModal",true);
},
/**
* Inclusion of Promise then to handle the response recieved from controller in a more appropriate way
**/
serverSideCall : function(component,action) {
return new Promise(function(resolve, reject) {
action.setCallback(this,
function(response) {
var state = response.getState();
if (state === "SUCCESS") {
var result = response.getReturnValue();
resolve(result);
} else {
reject(new Error(response.getError()));
}
});
$A.enqueueAction(action);
});
},
})
/** end of helper code **/
<aura:event type="COMPONENT" description="Event template" >
<aura:attribute name="selectedRecordId" type="list" />
</aura:event>
<!-- code for lightning Datatable With new and modify Option --->
<!-- parent component which will be using the dynamic lightning datatable -->
<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes,
flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes,
force:lightningQuickAction" access="global" >
<aura:attribute name="strObjectAPIName" type="String" default="Account"/>
<aura:attribute name="strFieldsAPIName" type="String" default="Name,Phone" />
<aura:attribute name="listSelectedObjectRecId" type="list" />
<aura:attribute name="noOfRecLimit" type="integer" default="5"/>
<aura:attribute name="displaySelectedRecid" type="boolean" default="false"/>
<aura:attribute name="isEditable" type="boolean" default="true"/>
<!--handle the event fired from the child components -->
<aura:handler name="callPassDynamicSelectedRecEvt" event="c:passDynamicSelectedRec" action="{!c.handleSelectedRecordEvent}"/>
<div class="container">
<c:dynamicLightningDataTable strObjectApiName="{!v.strObjectAPIName}"
fields="{!v.strFieldsAPIName}" noOfRecordsOnPage="{!v.noOfRecLimit}"
modifylabel="Edit" isEditable="{!v.isEditable}"/>
<aura:if isTrue="{!v.displaySelectedRecid}">
<aura:iteration items="{!v.listSelectedObjectRecId}" var="RecId">
Selected RecordIds : {!RecId}<br/>
</aura:iteration>
</aura:if>
</div>
</aura:component>
<!--End of lighnting.cmp ode that user dynamic datatable -->
/**
* code for its lightning controller that gives us the list of the selected record from the dynamic LIghtning datatable
**/
({
handleSelectedRecordEvent : function(component, event, helper) {
var selectedObjectReclist = event.getParam("selectedRecordId");
// set the handler attributes based on event data
component.set("v.listSelectedObjectRecId", selectedObjectReclist);
component.set("v.displaySelectedRecid",true);
}
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment