Author Archives: Biswajeet

About Biswajeet

Biswajeet is my Name, Success is my Aim and Challenge is my Game. Risk & Riding is my Passion and Hard Work is my Occupation. Love is my Friend, Perfection is my Habit and Smartness is my Style. Smiling is my Hobby, Politeness is my Policy and Confidence is my Power.

Lightning OverlayLibrary Modal

In Spring 18 Salesforce has provided lightning:overlayLibrary tag to displays messages via modals and popovers. This component requires API version 41.0 and later. lightning:overlayLibrary is not supported in the lightning application. It’s supported only on salesforce lightning experience Lightning, Console, Communities.

In this example, I’m using below components:

Main Component (Sample.cmp) – Will contain lightning:overlayLibrary tag with aura:id attribute and a lightning:button
Modal Content (OverlayLibraryModal.cmp) – The component responsible for containing all the content to show in the Modal as content.

Sample.cmp:

<!--Sample.cmp--> 
<aura:component  implements="flexipage:availableForAllPageTypes,flexipage:availableForRecordHome" access="global">
    <!--Declare Attribute-->
    <aura:attribute name="FirstName" type="String"/> 
    <aura:attribute name="LastName" type="String"/> 
    
    <lightning:overlayLibrary aura:id="overlayLib"/>
    
    <!--Component Start-->    
    <div class="slds-m-around--xx-large">
        <lightning:input name="fname" label="First Name" value="{!v.FirstName}" />
        <lightning:input name="lname" label="Last Name" value="{!v.LastName}" />
        <br/>
        <lightning:button variant="brand" label="Show Modal" onclick="{!c.handleShowModal}"/>
    </div>
    <!--Component End-->
</aura:component>

SampleController.js:

({
    handleShowModal: function(component) {
        var fName = component.get("v.FirstName");
        var lName = component.get("v.LastName");
        $A.createComponent("c:OverlayLibraryModal",
                           {
                               "FirstName" : fName,
                               "LastName" : lName
                           },
                           function(content, status) {
                               if (status === "SUCCESS") {
                                   var modalBody = content;
                                   component.find('overlayLib').showCustomModal({
                                       header: "Welcome to Biswajeet Samal's Blog",
                                       body: modalBody, 
                                       showCloseButton: true,
                                       closeCallback: function(ovl) {
                                           console.log('Overlay is closing');
                                       }
                                   }).then(function(overlay){
                                       console.log("Overlay is made");
                                   });
                               }
                           });
    }
})

OverlayLibraryModal.cmp:

<aura:component access="global">
    <!--Declare Attribute-->
    <aura:attribute name="FirstName" type="String"/> 
    <aura:attribute name="LastName" type="String"/> 
    <lightning:overlayLibrary aura:id="overlayLib"/>
    
    <!--Component Start-->  
    <div class="slds-m-around--xx-large">
        <p>{!v.FirstName} &nbsp; {!v.LastName} </p>
        <br/>
        <lightning:button variant="brand" label="Cancel" onclick="{!c.handleCloseModal}"/>
    </div>
    <!--Component End-->
</aura:component>

OverlayLibraryModalController.js:

({
    handleCloseModal: function(component, event, helper) {
        //Close the Modal Window
        component.find("overlayLib").notifyClose();
    }
})

Output:

Set or Modify Field Values in Onsubmit Event of lightning:recordeditform

Sometimes we can have a requirement to add or modify field values in onsubmit event of lightning:recordeditform. In below example, I’m creating “Lead” object record using lightning:recordeditform and in onsubmit event, I’m adding “Description” field value of “Lead” object.

Lightning Component:

<!--Sample.cmp--> 
<aura:component implements="flexipage:availableForAllPageTypes,force:appHostable">
    
    <!--Component--> 
    <div class="slds-m-around--xx-large">
        <lightning:card title="Lead" iconName="standard:lead" class="slds-p-around_medium">
            <lightning:recordEditForm aura:id="leadCreateForm" objectApiName="Lead" onsubmit="{!c.handleOnSubmit}">
                <lightning:messages />
                
                <div class="slds-grid">
                    <div class="slds-col slds-size_1-of-2 slds-p-around_medium">
                        <lightning:inputField fieldName="FirstName"></lightning:inputField>
                    </div>
                    <div class="slds-col slds-size_1-of-2 slds-p-around_medium">
                        <lightning:inputField fieldName="LastName"></lightning:inputField>
                    </div>
                </div>
                
                <div class="slds-grid">
                    <div class="slds-col slds-size_1-of-2 slds-p-around_medium">
                        <lightning:inputField fieldName="Email"></lightning:inputField>
                    </div>
                    <div class="slds-col slds-size_1-of-2 slds-p-around_medium">
                        <lightning:inputField fieldName="Phone"></lightning:inputField>
                    </div>
                </div>
                
                <div class="slds-grid">
                    <div class="slds-col slds-size_1-of-2 slds-p-around_medium">
                        <lightning:inputField fieldName="Company"></lightning:inputField>
                    </div>
                </div>
                
                <lightning:button type="submit" label="Save" variant="brand"/>
            </lightning:recordEditForm>
        </lightning:card>
    </div>
</aura:component>

Lightning JS Controller:

({
    handleOnSubmit : function(component, event, helper) {
        event.preventDefault(); //Prevent default submit
        var eventFields = event.getParam("fields"); //get the fields
        eventFields["Description"] = 'Lead was created from Lightning RecordEditForm'; //Add Description field Value
        component.find('leadCreateForm').submit(eventFields); //Submit Form
    }
})

Get lightning:recordeditform Field Values in onsuccess Event

Sometimes we can have a requirement to get field values, record Id, record type Id, child relationships information in onsuccess event of lightning:recordeditform. In below example, I’m creating “Lead” object record using lightning:recordeditform and after successfully saving the record, getting the field values in onsuccess event.

Lightning Component:

<!--Sample.cmp--> 
<aura:component implements="flexipage:availableForAllPageTypes,force:appHostable">
    
    <!--Component--> 
    <div class="slds-m-around--xx-large">
        <lightning:card title="Lead" iconName="standard:lead" class="slds-p-around_medium">
            <lightning:recordEditForm aura:id="leadCreateForm" objectApiName="Lead" onsuccess="{!c.handleOnSuccess}">
                <lightning:messages />
                
                <div class="slds-grid">
                    <div class="slds-col slds-size_1-of-2 slds-p-around_medium">
                        <lightning:inputField fieldName="FirstName"></lightning:inputField>
                    </div>
                    <div class="slds-col slds-size_1-of-2 slds-p-around_medium">
                        <lightning:inputField fieldName="LastName"></lightning:inputField>
                    </div>
                </div>
                
                <div class="slds-grid">
                    <div class="slds-col slds-size_1-of-2 slds-p-around_medium">
                        <lightning:inputField fieldName="Email"></lightning:inputField>
                    </div>
                    <div class="slds-col slds-size_1-of-2 slds-p-around_medium">
                        <lightning:inputField fieldName="Phone"></lightning:inputField>
                    </div>
                </div>
                
                <div class="slds-grid">
                    <div class="slds-col slds-size_1-of-2 slds-p-around_medium">
                        <lightning:inputField fieldName="Company"></lightning:inputField>
                    </div>
                </div>
                
                <lightning:button type="submit" label="Save" variant="brand"/>
            </lightning:recordEditForm>
        </lightning:card>
    </div>
</aura:component>

Lightning JS Controller:

({
    handleOnSuccess : function(component, event, helper) {
        var param = event.getParams(); //get event params
        var fields = param.response.fields; //get all field info
        var childRelationships = param.response.childRelationships; //get child relationship info
        var recordTypeInfo = param.response.recordTypeInfo; //get record type info
        var recordId = param.response.id; //get record id
        
        console.log('Param - ' + JSON.stringify(param)); 
        console.log('Fields - ' + JSON.stringify(fields)); 
        console.log('Child Relationship - ' + JSON.stringify(childRelationships)); 
        console.log('Record Type Info - ' + JSON.stringify(recordTypeInfo)); 
        console.log('Record Id - ' + JSON.stringify(recordId)); 
        
        //get Record Edit Form Field Values
        console.log('FirstName - ' + fields.FirstName.value);
        console.log('LastName - ' + fields.LastName.value);
        console.log('Email - ' + fields.Email.value);
        console.log('Phone - ' + fields.Phone.value);
        console.log('Company - ' + fields.Company.value);
    }
})

Salesforce Lightning Datatable

Apex Controller:

public class SampleAuraController {
    
    //Get Contact List
    @AuraEnabled
    public static List<Contact> getContactList(Integer recordLimit, Integer recordOffset){
        Integer intLimit = Integer.valueof(recordLimit);
        Integer intOffset = Integer.valueof(recordOffset);
        List<Contact> conList = new List<Contact>();
        conList = [SELECT Id, Name, Email, Phone FROM Contact LIMIT :intLimit Offset :intOffset];
        return conList;
    }
    
    //Get Total Number of Contacts
    @AuraEnabled
    public static Integer getTotalContacts(){
        AggregateResult results = [SELECT Count(Id) TotalContacts  From Contact];
        Integer totalContacts = (Integer)results.get('TotalContacts') ; 
        return totalContacts;
    } 
    
    //Delete Contact
    @AuraEnabled
    public static void deleteContact(Contact con){
        Delete con;
    } 
}

Lightning Component:

<!--Sample.cmp--> 
<aura:component controller="SampleAuraController" implements="flexipage:availableForAllPageTypes,force:appHostable">
    
    <!--Declare Attributes-->
    <aura:attribute name="data" type="Object"/>
    <aura:attribute name="columns" type="List"/>
    <aura:attribute name="selectedRowsCount" type="Integer" default="0"/>
    <aura:attribute name="selectedRowsDetails" type="Object" />
    <aura:attribute name="selectedRowsList" type="List" />
    <aura:attribute name="maxRowSelection" type="Integer" default="10"/>
    <aura:attribute name="selectedRows" type="List" />
    <aura:attribute name="enableInfiniteLoading" type="Boolean" default="true"/>
    <aura:attribute name="initialRows" type="Integer" default="10"/>
    <aura:attribute name="rowsToLoad" type="Integer" default="10"/>
    <aura:attribute name="totalNumberOfRows" type="Integer" default="10"/>
    <aura:attribute name="loadMoreStatus" type="String" default="Please scroll down to load more data"/>
    <aura:attribute name="showRowNumberColumn" type="Boolean" default="false"/>
    <aura:attribute name="rowNumberOffset" type="Integer" default="0"/>
    <aura:attribute name="rowsToAdd" type="Integer" default="10"/>
    <aura:attribute name="currentCount" type="Integer" default="10"/>
    <aura:attribute name="sortedBy" type="String"/>
    <aura:attribute name="sortedDirection" type="String"/>
    <aura:attribute name="defaultSortDirection" type="String"/>
    
    <!--Declare Handlers-->
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    
    <!--Component Start-->
    <div class="slds-m-around_xx-large" style="height: 300px">
        <lightning:datatable columns="{!v.columns}"
                             data="{!v.data}"
                             keyField="Id"
                             showRowNumberColumn="true"
                             rowNumberOffset="0"
                             onrowaction="{!c.handleRowAction}"
                             selectedRows="{!v.selectedRows}"
                             maxRowSelection="{!v.maxRowSelection}"
                             onrowselection="{!c.handleSelectedRow}"
                             enableInfiniteLoading="true"
                             loadMoreOffset="{!v.loadMoreOffset}"
                             sortedBy="{!v.sortedBy}"
                             sortedDirection="{!v.sortedDirection}"
                             defaultSortDirection="{!v.defaultSortDirection }"
                             onsort="{!c.handleColumnSorting}"
                             onloadmore="{!c.handleLoadMoreContacts}"/>
        <br/>
        <div class="slds-float_left">
            <strong>Total Rows : {!v.totalNumberOfRows}</strong>
            &nbsp;&nbsp;
            <strong>Selected Rows: {!v.selectedRowsCount }</strong>
        </div>
        <div class="slds-float_right">
            <strong>{!v.loadMoreStatus}</strong>
        </div>
        <br/>
        <br/>
        <div class="slds-float_left">
            <lightning:button label="Get Selected Contacts"  variant="brand" onclick="{!c.handleSelectedRows}"/>    
        </div>
    </div>
    <!--Component End-->
</aura:component>

Lightning Component JS Controller:

({
    doInit : function(component, event, helper) {
        helper.getTotalNumberOfContacts(component);
        helper.getColumnAndAction(component);
        helper.getContacts(component);
    },
    
    handleLoadMoreContacts: function (component, event, helper) {
        event.getSource().set("v.isLoading", true);
        component.set('v.loadMoreStatus', 'Loading....');
        helper.getMoreContacts(component, component.get('v.rowsToLoad')).then($A.getCallback(function (data) {
            if (component.get('v.data').length == component.get('v.totalNumberOfRows')) {
                component.set('v.enableInfiniteLoading', false);
                component.set('v.loadMoreStatus', 'No more data to load');
            } else {
                var currentData = component.get('v.data');
                var newData = currentData.concat(data);
                component.set('v.data', newData);
                component.set('v.loadMoreStatus', 'Please scroll down to load more data');
            }
            event.getSource().set("v.isLoading", false);
        }));
    },
    
    handleSelectedRows: function (component, event, helper) {
        var data = component.get('v.data');
        var selectedRowList =  component.get("v.selectedRowsList");
        console.log('selectedRowList-' + selectedRowList);
    },
    
    handleSelectedRow: function(component, event, helper){
        var selectedRows = event.getParam('selectedRows');
        component.set("v.selectedRowsCount", selectedRows.length);
        let obj =[] ; 
        for (var i = 0; i < selectedRows.length; i++){
            obj.push({Name:selectedRows[i].Name});
        }
        component.set("v.selectedRowsDetails", JSON.stringify(obj) );
        component.set("v.selectedRowsList", event.getParam('selectedRows'));
    },
    
    handleRowAction: function (component, event, helper) {
        var action = event.getParam('action');
        switch (action.name) {
            case 'new':
                helper.createContactRecord(component, event);
                break;
            case 'edit':
                helper.editContactRecord(component, event);
                break;
            case 'delete':
                helper.deleteContactRecord(component, event);
                break;
            case 'view':
                helper.viewContactRecord(component, event);
                break;
        }
    },
    
    handleColumnSorting: function (component, event, helper) {
        var fieldName = event.getParam('fieldName');
        var sortDirection = event.getParam('sortDirection');
        component.set("v.sortedBy", fieldName);
        component.set("v.sortedDirection", sortDirection);
        helper.sortData(component, fieldName, sortDirection);
    },
})

Lightning Component JS Helper:

({
    getContacts : function(component) {
        var action = component.get("c.getContactList");
        action.setParams({
            "recordLimit": component.get("v.initialRows"),
            "recordOffset": component.get("v.rowNumberOffset")
        });
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS" ) {
                var resultData = response.getReturnValue();
                component.set("v.data", resultData);
                component.set("v.currentCount", component.get("v.initialRows"));
            }
        });
        $A.enqueueAction(action);
    },
    
    getTotalNumberOfContacts : function(component) {
        var action = component.get("c.getTotalContacts");
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS" ) {
                var resultData = response.getReturnValue();
                component.set("v.totalNumberOfRows", resultData);
            }
        });
        $A.enqueueAction(action);
    },
    
    getColumnAndAction : function(component) {
        var actions = [
            {label: 'New', name: 'new'},
            {label: 'Edit', name: 'edit'},
            {label: 'Delete', name: 'delete'},
            {label: 'View', name: 'view'}
        ];
        component.set('v.columns', [
            {label: 'Name', fieldName: 'Name', type: 'text', sortable:true},
            {label: 'Email', fieldName: 'Email', type: 'email', sortable:true},
            {label: 'Phone', fieldName: 'Phone', type: 'phone', sortable:true},
            {type: 'action', typeAttributes: { rowActions: actions } } 
        ]);
    },
    
    getMoreContacts: function(component , rows){
        return new Promise($A.getCallback(function(resolve, reject) {
            var action = component.get('c.getContactList');
            var recordOffset = component.get("v.currentCount");
            var recordLimit = component.get("v.initialRows");
            action.setParams({
                "recordLimit": recordLimit,
                "recordOffset": recordOffset 
            });
            action.setCallback(this, function(response) {
                var state = response.getState();
                if(state === "SUCCESS"){
                    var resultData = response.getReturnValue();
                    resolve(resultData);
                    recordOffset = recordOffset+recordLimit;
                    component.set("v.currentCount", recordOffset);   
                }                
            });
            $A.enqueueAction(action);
        }));
    },
    
    sortData: function (component, fieldName, sortDirection) {
        var data = component.get("v.data");
        var reverse = sortDirection !== 'asc';
        data.sort(this.sortBy(fieldName, reverse))
        component.set("v.data", data);
    },
    
    sortBy: function (field, reverse, primer) {
        var key = primer ?
            function(x) {return primer(x[field])} :
        function(x) {return x[field]};
        reverse = !reverse ? 1 : -1;
        return function (a, b) {
            return a = key(a), b = key(b), reverse * ((a > b) - (b > a));
        }
    },
    
    viewContactRecord : function(component, event) {
        var row = event.getParam('row');
        var recordId = row.Id;
        var navEvt = $A.get("event.force:navigateToSObject");
        navEvt.setParams({
            "recordId": recordId,
            "slideDevName": "detail"
        });
        navEvt.fire();
    },
    
    deleteContactRecord : function(component, event) {
        var action = event.getParam('action');
        var row = event.getParam('row');
        
        var action = component.get("c.deleteContact");
        action.setParams({
            "con": row
        });
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS" ) {
                var rows = component.get('v.data');
                var rowIndex = rows.indexOf(row);
                rows.splice(rowIndex, 1);
                component.set('v.data', rows);
                
                var toastEvent = $A.get("e.force:showToast");
                toastEvent.setParams({
                    "title": "Success!",
                    "message": "The record has been delete successfully."
                });
                toastEvent.fire();
            }
        });
        $A.enqueueAction(action);
    },
    
    editContactRecord : function(component, event) {
        var row = event.getParam('row');
        var recordId = row.Id;
        var editRecordEvent = $A.get("e.force:editRecord");
        editRecordEvent.setParams({
            "recordId": recordId
        });
        editRecordEvent.fire();
    },
    
    createContactRecord : function (component, event) {
        var createRecordEvent = $A.get("e.force:createRecord");
        createRecordEvent.setParams({
            "entityApiName": "Contact"
        });
        createRecordEvent.fire();
    }
})

Output:

Salesforce Lightning Button Menu

Lightning Component:

<!--Sample.cmp--> 
<aura:component implements="flexipage:availableForAllPageTypes, force:appHostable">
    <div class="slds-m-around_xx-large">
        <lightning:buttonMenu  iconName="utility:settings" alternativeText="Action" onselect="{!c.handleMenuSelect}">
            <lightning:menuItem label="New" iconName="utility:new" value="new"/>
            <lightning:menuItem label="Edit" iconName="utility:edit" value="edit"/>
            <lightning:menuItem label="Delete" iconName="utility:delete" value="delete"/>
        </lightning:buttonMenu>
    </div>
</aura:component>

Lightning Component JS Controller:

({    
    handleMenuSelect: function(component, event, helper) {
        var selectedMenu = event.detail.menuItem.get("v.value");
        console.log('selectedMenu-' + selectedMenu);
        switch(selectedMenu) {
            case "new":
                //do create
                break;
            case "edit":
                //do edit
                break;
            case "delete":
                //do delete
                break;
        }
    }
})

Output:

Reference: lightning:buttonMenu lightning:menuItem