- Header – The title of the modal
- Body – Main content of the Modal
- Footer – Content that relies on the bottom of the Modal. For example, Cancel, Save, Update buttons.
In this example, we will use 3 components and the details are given below
- Main Component (MainComponent.cmp) – Will contain lightning:overlayLibrary tag with aura:id attribute and a lightning:button
- Modal Content (ModalContent.cmp) – The component responsible for containing all the content to show in the Modal as content
- Modal Footer(ModalFooter.cmp) – The component will contain 2 buttons one for closing the Modal and other for performing the action as per requirement.
Step1- Create modalContent.cmp – File -> New -> Lightning Component -> modalContent ->
Component displays the contact details usning Lightning Datatable and have many new features. Use below code
modalContent.cmp
[codesyntax lang=”xml” container=”div” doclinks=”1″]
<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId,force:lightningQuickAction" controller="Spring18ReleaseController" access="global" > <aura:handler name='init' action="{!c.init}" value="{!this}" /> <aura:attribute name="conList" type="Object"/> <aura:attribute name="columns" type="List"/> <aura:attribute name='showRecordid' type='String' /> <!-- Lightning Datatale Start --> <lightning:datatable aura:id="contactTable" data="{!v.conList}" columns="{!v.columns}" onsort="{!c.updateColumnSorting}" hideCheckboxColumn="false" onrowaction="{!c.handleRowAction}" keyField="id"> </lightning:datatable> </aura:component>
[/codesyntax]
modalContentController.js
[codesyntax lang=”javascript” container=”div” doclinks=”1″]
({ init: function (cmp, event, helper) { var headerActions = [ { label: 'All', checked: true, name:'all' }, { label: 'Published', checked: false, name:'show_published' }, { label: 'Unpublished', checked: false, name:'show_unpublished' }, ]; var actions = helper.getRowActions.bind(this, cmp); cmp.set('v.columns', [ { label: 'Name', fieldName: 'Name', type: 'text', sortable:true }, { label: 'Title', fieldName: 'Title', type: 'text', sortable:true }, { label: 'Phone', fieldName: 'Phone', type: 'phone', sortable:true }, { label: 'Email', fieldName: 'Email', type: 'email', sortable:true }, { type: 'action', typeAttributes: { rowActions: actions } } ]); helper.onInit(cmp, event, helper); }, handleRowAction: function (cmp, event, helper) { var action = event.getParam('action'); var row = event.getParam('row'); switch (action.name) { case 'activate': helper.activateContact(cmp, row) break; case 'deactivate': helper.deactivateContact(cmp, row); break; case 'Delete': helper.deleteContact(cmp, row); break; case 'Edit' : helper.editContact(cmp, row); break; case 'Show_Details' : helper.showDetails(cmp, row); break; } }, // Client-side controller called by the onsort event handler updateColumnSorting: function (cmp, event, helper) { var fieldName = event.getParam('fieldName'); var sortDirection = event.getParam('sortDirection'); var tableComp = cmp.find('contactTable'); // assign the latest attribute with the sorted column fieldName and sorted direction tableComp.set("v.sortedBy", fieldName); tableComp.set("v.sortedDirection", sortDirection); helper.sortData(cmp, fieldName, sortDirection); } })
[/codesyntax]
modalContentHelper.js
[codesyntax lang=”javascript” container=”div” doclinks=”1″]
({ onInit : function(component, event, helper) { var action = component.get('c.fetchContcts'); action.setCallback(this, function(response){ var responseValue = response.getReturnValue(); component.set('v.conList', responseValue); }); $A.enqueueAction(action); }, getRowActions: function (cmp, row, doneCallback) { var actions = []; actions.push({ 'label': 'Edit', 'iconName': 'action:edit', 'name': 'Edit' }); actions.push({ 'label': 'Delete', 'iconName': 'action:delete', 'name': 'Delete' }); actions.push({ 'label': 'Show Details', 'iconName': 'action:preview', 'name': 'Show_Details' }); /*if (row['isActive__c']) { actions.push({ 'label': 'Deactivate', 'iconName': 'utility:block_visitor', 'name': 'deactivate' }); } else { actions.push({ 'label': 'Activate', 'iconName': 'utility:adduser', 'name': 'activate' }); }*/ // simulate a trip to the server setTimeout($A.getCallback(function () { doneCallback(actions); }), 200); }, activateContact: function (cmp, row) { var rows = cmp.get('v.conList'); var rowIndex = rows.indexOf(row); rows[rowIndex]['isActive__c'] = true; rows[rowIndex]['active'] = 'Active'; cmp.set('v.conList', rows); }, deactivateContact: function (cmp, row) { var rows = cmp.get('v.conList'); var rowIndex = rows.indexOf(row); rows[rowIndex]['isActive__c'] = false; rows[rowIndex]['active'] = 'Inactive'; cmp.set('v.conList', rows); }, deleteContact : function (component, contact) { // Put the logic for deleting the contact Here }, editContact : function (component, contact) { // Open the modal to Edit complete Contact in Modal using force:recordEdit }, showDetails : function (component, contact) { component.set('v.showRecordid', contact.Id); }, sortData: function (cmp, fieldName, sortDirection) { var data = cmp.get("v.conList"); var reverse = sortDirection !== 'asc'; //sorts the rows based on the column header that's clicked data.sort(this.sortBy(fieldName, reverse)) cmp.set("v.conList", data); }, sortBy: function (field, reverse, primer) { var key = primer ? function(x) {return primer(x[field])} : function(x) {return x[field]}; //checks if the two rows should switch places reverse = !reverse ? 1 : -1; return function (a, b) { return a = key(a), b = key(b), reverse * ((a > b) - (b > a)); } }, GetSortOrderAsc : function(component,prop){ var a=component.get('v.conList'); return function(a, b) { if (a[prop] > b[prop]) { return 1; } else if (a[prop] < b[prop]) { return -1; } return 0; } }, GetSortOrderDsc : function(component,prop){ var a=component.get('v.conList'); return function(a, b) { if (a[prop] > b[prop]) { return -1; } else if (a[prop] < b[prop]) { return 1; } return 0; } } })
[/codesyntax]
Step2 – Create modalFooter.cmp File -> New -> lightning Component -> modalFooter ->
This component also use the lightning:overlayLibrary tag and the same aura:id that we will define in mainComponent. For footer component use below code
modalFooter.cmp
[codesyntax lang=”xml” container=”div” doclinks=”1″]
<aura:component > <lightning:overlayLibrary aura:id="overlayLib"/> <lightning:button name="cancel" label="Cancel" onclick="{!c.handleCancel}"/> <lightning:button name="ok" label="OK" variant="brand" onclick="{!c.handleOK}"/> </aura:component>
[/codesyntax]
modalFooterController.js
[codesyntax lang=”javascript” container=”div” doclinks=”1″]
({ handleCancel : function(component, event, helper) { //closes the modal or popover from the component component.find("overlayLib").notifyClose(); }, handleOK : function(component, event, helper) { //do something } })
[/codesyntax]
Step3 – Create mainComponent.cmp File -> New -> lightning Component -> mainComponent ->
This component contains a button by clicking on which a modal will open displaying the Pagination using Lighning Datatable. Use below code for the component
mainComponent.cmp
[codesyntax lang=”xml” container=”div” doclinks=”1″]
<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId"> <!-- lightning:overlayLibrary responsible to show/hide the modal using standard Lightning Library --> <lightning:overlayLibrary aura:id="overlayLib"/> <!-- lightning:overlayLibrary End--> <!-- Put a lightning button clicking on which modal will open End --> <lightning:button name="modal" label="Show Modal" onclick="{!c.handleShowModal}"/> <!-- Put a lightning button clicking on which modal will open End --> </aura:component>
[/codesyntax]
mainComponentController.js
In the controller, we are using $A.createComponents to create the components(multiple) dynamically so that it will also improve the performance of the Lightning Components.
[codesyntax lang=”javascript” container=”div” doclinks=”1″]
({ handleShowModal : function (component, event, helper) { var modalBody; var modalFooter; $A.createComponents([ ["c:modalContent",{}], ["c:modalFooter",{}] ], function(components, status){ if (status === "SUCCESS") { modalBody = components[0]; modalFooter = components[1]; component.find('overlayLib').showCustomModal({ header: "Paginaniton In Lightning", body: modalBody, footer: modalFooter, showCloseButton: true, cssClass: "my-modal,my-custom-class,my-other-class", closeCallback: function() { } }); } } ); } })
[/codesyntax]
Step4 – Create an Apex Class Spring18ReleaseController.
[codesyntax lang=”java” container=”div” doclinks=”1″]
public class Spring18ReleaseController { @AuraEnabled public static List<Contact> fetchContcts(){ List<Contact> contactList = new List<Contact>(); contactList = [Select Id, Name, Email, Title, Phone, isActive__c From Contact Limit 5]; return contactList; } public class lightningTableColumnWrapper{ @AuraEnabled public String label { get; set; } @AuraEnabled public String fieldName { get; set; } @AuraEnabled public String type { get; set; } @AuraEnabled public Boolean sortable { get; set; } } public class lightningTableDataWrapper{ @AuraEnabled public Contact con { get; set; } @AuraEnabled public String accountName { get; set; } } public class lightningTableWrapper{ @AuraEnabled public List<lightningTableColumnWrapper> tableColumnWrapper { get; set; } @AuraEnabled public List<lightningTableDataWrapper> tableDataWrapper { get; set; } } }
[/codesyntax]
Step5 – Add mainComponent.cmp component into any Object Detail Page to see the output. In the example, I will add to the Account Detail page.
Output: – See the output below
Please let me know if you do have any issue/suggestion. You can let us your thoughts into the comment section or you can tweet me here.
Resources: –
Good one!!
Thank You 🙂
I am trying to pass attributes while creating component but 2 way binding is not working.
$A.createComponents([
[“c:GRG_MeetingAppraochModal”,{
‘record’ : component.get(“v.record”),
‘recordId’ : component.get(“v.recordId”),
‘selectedAppraoches’ : component.get(“v.selectedAppraoches”)
}],
[“c:GRG_MeetingAppraochFooterModal”,{
‘record’ : component.get(“v.record”),
‘recordId’ : component.get(“v.recordId”),
‘selectedAppraoches’ : component.get(“v.selectedAppraoches”)
}]
],
function(components, status) {
if (status === “SUCCESS”) {
modalBody = components[0];
modalFooter = components[1];
component.find(‘overlay-modal’).showCustomModal({
header: “Approach List”,
body: modalBody,
footer: modalFooter,
showCloseButton: true,
cssClass: “approach-modal slds-modal_large”,
closeCallback: function(){
console.log(components[0].get(“v.selectedAppraoches”)); /// I can’t see values which user has selected in modal. It shows me undefined.
console.log(components[0].get(“v.recordId”)); /// I even can’t see values for recordId also.
}
});
}
});
Hi Saurabh,
What are you trying to achieve here? closeCallback method called when you are closing the Modal.
Please let me know so that I can help you in the best way.
Regards,
SFDCPanther
I think Spring18ReleaseController Apex class is missing.
Hi Ravi,
Thanks for pointing out. Now, I have added the same.
Thanks,
SFDCPanther
I am trying to use this exactly the same but instead of in a lightning record page I want to use it in an aura:application. It wont work though. Any idea why?
This works great within lightning record page.
Also, if I call this component from a quick action it works but it throws an error after I close it.
Hi Aaron,
As this is a beta feature it is not supported in the Standalone application. For this, you need to develop the custom solution using the SLDS.
Is it possible to update the Footer of the lightning overlay component? I’d like to update the buttons on the footer, and not sure if I can access the Header, footer, etc.
Yes. We can.
Hi Amit, I’ve a form in Overlay body as a different component and I’ve created a component for overlay footer with 2 buttons close and submit. On click of submit I want all form fields data, how to get it?
Hi Manish,
You can follow the below approach.
1 – Create a Lightning Standalone Application
2 – Put Body and Footer Component inside this Application
3 – Create an Application Event with Required Attribute
4 – Fire the event from the component which is having the records
5 – Handle the Event in the Footer Component
6 – Now, you will have the data in Footer component and now call the Apex method pass the params and save the data into apex.
Hope this will help 🙂
Thanks,
SFDCPanther