Salesforce Lightning Component to insert records from Excel
Hey guys, I have posted the video at bottom of same steps mentioned in the blog. Today in this post we are going to learn that how we can insert records in custom object from Salesforce Lightning Component. also we will learn that how to call/ invoke server side apex method from lightning component (Aura)
Step 1/4:
Creating Object & Fields:
Create Custom Object: 'Employee__c'Create Field 'Name' & Datatype: 'Text'
Create Field 'First_Name__c' & Datatype: 'Text'
Create Field 'Email_Id__c' & Datatype: 'Text'
Create Field 'Joining_Date__c' & Datatype: 'Date'
Create Field 'Last_Name__c' & Datatype: 'Text'
Create Field 'Phone_Number__c' & Datatype: 'Text'
Add Static Resource:
Add Static Resource: XLSXDownload JS Library from: JS Library
Now Edit it: Just add one line in this JS
window.XLSX = XLSX;
Step 2/4:
Create Apex Class:
ExcelImportController.apxc1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | public with sharing class ExcelImportController { public virtual class BulkEmployeeException extends Exception {} /* * @param base64Data : Content of the File in JSON format * @param fileName : File Name * @param contentType : Type of the File (Excel) */ @AuraEnabled public static void parseFile(String base64Data, String fileName) { System.debug('In ParseFile'); try { System.debug('JSONfromJS::'+base64Data); System.debug('fileNamefromJS::'+fileName); Blob blobData = Blob.valueOf(base64Data); System.debug('blobData::'+blobData); createEmployeeBatchRecords(blobData); }catch(BulkEmployeeException e){ System.debug('BulkEmployeeException::::'+e.getMessage()); }catch (Exception e) { System.debug('Exception::::'+e); } } /** * @description: This method is used to create the Claim Batch Stage records based on the CSV Data as Input * @param blobData: Content of the File Uploaded by the User in Blob format */ public static void createEmployeeBatchRecords(Blob blobData) { String csvAsString; String[] csvFileLines; System.debug('blobData:::'+blobData); csvAsString = blobData.toString(); system.debug('Before JSON Formator csvAsString::' + csvAsString); String csvAsString1 = jsonFormator(csvAsString); System.debug('After JSON Formator csvAsString1::'+csvAsString1); List<JSON2ApexController> objList = JSON2ApexController.parse(csvAsString1); System.debug('After JSON deserialize objList::'+objList); System.debug('objList[0]::'+objList[0]); List<Employee__c> batchEmployeeList = new List<Employee__c>(); for(JSON2ApexController item: objList) { Employee__c batchEmployeeRecord = new Employee__c(); batchEmployeeRecord.Name = item.EmployeeName; batchEmployeeRecord.Email_Id__c = item.EmailId; batchEmployeeRecord.First_Name__c = item.FirstName; batchEmployeeRecord.Last_Name__c = item.LastName; batchEmployeeRecord.Phone_Number__c = item.PhoneNumber; Date standardDate = convertDateToStandardDate(item.JoiningDate); batchEmployeeRecord.Joining_Date__c = standardDate; batchEmployeeList.add(batchEmployeeRecord); } try{ database.insert(batchEmployeeList); } catch(Exception e) { System.debug('Insert Exception::::'+e.getMessage()); } } public static List<JSON2ApexController> parse(String jsonString) { return (List<JSON2ApexController>) System.JSON.deserialize(jsonString, List<JSON2ApexController>.class); } public class JSON2ApexController { public String EmployeeName; public String EmailId; public String FirstName; public String LastName; public String PhoneNumber; public String JoiningDate; } public static String jsonFormator(String jsonString) { String target = 'Employee Name'; String replacement = 'EmployeeName'; String jsonString1 = jsonString.replace(target, replacement); target = 'Email Id'; replacement = 'EmailId'; jsonString1 = jsonString1.replace(target, replacement); target = 'First Name'; replacement = 'FirstName'; jsonString1 = jsonString1.replace(target, replacement); target = 'Last Name'; replacement = 'LastName'; jsonString1 = jsonString1.replace(target, replacement); target = 'Phone Number'; replacement = 'PhoneNumber'; jsonString1 = jsonString1.replace(target, replacement); target = 'Joining Date (DD-MMM-YY)'; replacement = 'JoiningDate'; jsonString1 = jsonString1.replace(target, replacement); return jsonString1; } public static Date convertDateToStandardDate(String inputDate){ // input Date in format : 10-Feb-2019 // inputDateArray (10,Feb,2019) try{ String[] inputDateArray = inputDate.split('-'); String monthInUpperCase = inputDateArray[1].toUpperCase(); Integer month = 0; switch on monthInUpperCase { when 'JAN' { month = 1; } when 'FEB' { month = 2; } when 'MAR' { month = 3; } when 'APR' { month = 4; } when 'MAY' { month = 5; } when 'JUN' { month = 6; } when 'JUL' { month = 7; } when 'AUG' { month = 8; } when 'SEP' { month = 9; } when 'OCT' { month = 10; } when 'NOV' { month = 11; } when 'DEC' { month = 12; } when else { month = 0; } } Date todayDate = System.today(); Date standardDate; String currentCentury = String.valueOf(todayDate.year()).substring(0,2); String finalYear = currentCentury+inputDateArray[2]; if(month == 0){ throw new BulkEmployeeException('Invalid Date'); }else{ standardDate = Date.newInstance(Integer.valueOf(finalYear),month,Integer.valueOf(inputDateArray[0])); } return standardDate; }catch(Exception e){ throw new BulkEmployeeException('Exception:: '+inputDate); } } } |
Create Lightning Event:
ExcelImportEvent.evt1 2 3 4 5 6 | <aura:event type="COMPONENT" description="ExcelImportEvent"> <aura:attribute type="String" name="type" description="Type of the event: SUCCESS, ERROR" required="true"/> <aura:attribute type="String" name="message" description="Message" required="false"/> <aura:attribute type="String" name="fileName" description="File name" required="false"/> <aura:attribute type="Object" name="table" description="Parsed Excel table" required="false"/> </aura:event> |
Create Lightning Component:
ExcelImport.cmp1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <aura:component controller="ExcelImportController" implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes" access="global" description="Component to import .xlsx files in Lightning"> <ltng:require scripts="{!$Resource.XLSX}"/> <aura:registerEvent name="onImport" type="c:ExcelImportEvent"/> <aura:attribute name="content" type="String" /> <aura:attribute name="file" type="Object" /> <aura:attribute name="recordTypeMap" type="Map" default="" /> <aura:attribute name="label" type="String" description="Label for input" default="Import Excel File" required="false"/> <aura:attribute name="class" type="String" description="Additional styles" required="false"/> <aura:attribute name="variant" type="String" description="Input variant" required="false" default="standard"/> <aura:attribute name="required" type="Boolean" description="Shows if input is mandatory" default="false"/> <aura:attribute name="disabled" type="Boolean" description="Displays input disabled" default="false"/> <aura:attribute name="accept" type="String" default=".xls, .xlsx"/> <aura:attribute name="stretchedDropzone" type="Boolean" description="Makes dropzone stretchable" default="false"/> <aura:attribute name="isLoading" type="Boolean" default="false" access="private"/> <aura:attribute name="fileSizeThreshold" type="Integer" description="Max file size in bytes, default 10mb" default="10000000" required="false"/> <aura:attribute name="messageFileSizeExceeded" type="String" default="File size exceeded" required="false"/> <aura:attribute name="messageNoFileSpecified" type="String" default="No file specified" required="false"/> <lightning:input type="file" label="{!v.label}" class="{!v.class + (v.stretchedDropzone ? ' bigger-drop-zone' : '') + (v.isLoading ? ' drop-zone-loading' : '')}" variant="{!v.variant}" required="{!v.required}" disabled="{!v.disabled}" onchange="{!c.onTableImport}" multiple="false" accept="{!v.accept}"/> </aura:component> |
Add Controller JS:
ExcelImportController.js1 2 3 4 5 6 | ({ onTableImport: function (cmp, evt, helper) { helper.disableExcelInput(cmp); helper.importTableAndThrowEvent(cmp, evt, helper); } }) |
Add Helper JS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | ({ disableExcelInput: function(cmp) { cmp.set("v.disabled", true); cmp.set("v.isLoading", true); }, enableExcelInput: function(cmp) { cmp.set("v.disabled", false); cmp.set("v.isLoading", false); }, importTableAndThrowEvent: function(cmp, evt, helper) { evt.stopPropagation(); evt.preventDefault(); try { const file = helper.validateFile(cmp, evt); cmp.set("v.file",file); helper.readExcelFile(cmp, file, helper) .then($A.getCallback(excelFile => { helper.throwSuccessEvent(cmp, excelFile); })) .catch($A.getCallback(exceptionMessage => { helper.throwExceptionEvent(cmp, exceptionMessage); })) .finally($A.getCallback(() => { helper.enableExcelInput(cmp); })) } catch (exceptionMessage) { helper.throwExceptionEvent(cmp, exceptionMessage); helper.enableExcelInput(cmp); } }, validateFile: function(cmp, evt) { const files = evt.getSource().get("v.files"); if (!files || files.length === 0 || $A.util.isUndefinedOrNull(files[0])) { throw cmp.get("v.messageNoFileSpecified"); } const file = files[0]; const fileSizeThreshold = cmp.get("v.fileSizeThreshold"); if (file.size > fileSizeThreshold) { throw (cmp.get("v.messageFileSizeExceeded") + ': ' + fileSizeThreshold + 'b'); } return file; }, readExcelFile: function(cmp, file, helper) { return new Promise(function (resolve, reject) { const fileReader = new FileReader(); fileReader.onload = event => { let filename = file.name; let binary = ""; new Uint8Array(event.target.result).forEach(function (byte) { binary += String.fromCharCode(byte); }); try { resolve({ "fileName": filename, "xlsx": XLSX.read(binary, {type: 'binary', header: 1}) }); console.log('XLSX.read::'+XLSX.read(binary, {type: 'binary', header: 1})); console.log('END1::'); var workbook = XLSX.read(binary, { type: 'binary' }); var sheet_name_list = workbook.SheetNames; console.log(XLSX.utils.sheet_to_json(workbook.Sheets[sheet_name_list[0]])); var XL_row_object = XLSX.utils.sheet_to_json(workbook.Sheets[sheet_name_list[0]]); console.log('XL_row_object::'+XL_row_object); var json_object = JSON.stringify(XL_row_object); cmp.set("v.content", json_object); console.log('After content set::'+cmp.get("v.content")); helper.parseFile1(cmp); console.log('END2::'); } catch (error) { reject(error); } }; console.log('After content set::'+cmp.get("v.content")); fileReader.readAsArrayBuffer(file); }); }, throwExceptionEvent: function(component, message) { const errorEvent = component.getEvent("onImport"); errorEvent.setParams({ "type": "ERROR", "message": message }); errorEvent.fire(); }, throwSuccessEvent: function(component, parsedFile) { const successEvent = component.getEvent("onImport"); successEvent.setParams({ "type": "SUCCESS", "fileName": parsedFile.fileName, "table": parsedFile.xlsx }); successEvent.fire(); }, parseFile1: function (cmp) { console.log('json_object::'); console.log('KInside::'+cmp.get("v.content")); var file = cmp.get("v.file"); var action = cmp.get("c.parseFile"); action.setParams({ base64Data: cmp.get("v.content"), fileName: file.name, }); action.setCallback(this, function (response) { if (response.getState() == "SUCCESS") { console.log('Successful'); } else { console.log('errorMsg'); } }); $A.enqueueAction(action); } }) |
Step 3/4:
Create one Excel with extension .xls & Columns:Employee Name
Email Id
First Name
Last Name
Phone Number
Joining Date (DD-MMM-YY)
Excel should look like this:
Step 4/4:
Now add this component to Home Page & upload your Excel File.You can add Exception Handing & Toast Messages!
Please contact for any Ideas/Suggestions/Collaborations: krishna1096@gmail.com | 9921034154
Great....
ReplyDeleteCan you please post the test class as well
ReplyDeleteCould you please provide the test class? @krishna kulkarni
DeleteThis comment has been removed by the author.
ReplyDeleteHello ,
ReplyDeleteThanks a lot for the code !
Could implement as per the blog instructions but records are not created in SF.
hello, good solution, I have a question, How many rows this solution supports?
ReplyDeleteHello,
ReplyDeleteThankyou for posting this, May I ask a question?
I am very new to Salesforce, and may have done something wrong following the instructions, but cant work out what?
On upload of the file, get the following error:
[NoErrorObjectAvailable] Script error.
a()@https://static.lightning.force.com/aus2s.sfdc-vwfla6/auraFW/javascript/7FPkrq_-upw5gdD4giTZpg/aura_prod.js:1010:196
{anonymous}()@https://static.lightning.force.com/aus2s.sfdc-vwfla6/auraFW/javascript/7FPkrq_-upw5gdD4giTZpg/aura_prod.js:1010:389
dispatchEvent()@https://static.lightning.force.com/aus2s.sfdc-vwfla6/auraFW/javascript/7FPkrq_-upw5gdD4giTZpg/aura_prod.js:21:19540
_e.dispatchEvent()@https://static.lightning.force.com/aus2s.sfdc-vwfla6/auraFW/javascript/7FPkrq_-upw5gdD4giTZpg/aura_prod.js:13:14057
_e._dispatchChangeEventWithDetail()@https://picnic--staging.lightning.force.com/components/lightning/input.js:1:36147
_e._dispatchChangeEvent()@https://picnic--staging.lightning.force.com/components/lightning/input.js:1:37721
_e.handleChange()@https://picnic--staging.lightning.force.com/components/lightning/input.js:1:34942
Any ideas on how to diagnose this??
Winter '22
Excellent blog I visit this blog it's really awesome. The important thing is that in this blog content written clearly and understandable. The content of information is very informative.We are also providing the best services click on below links to visit our website.
ReplyDeleteOracle Fusion HCM Training
Workday Training
Okta Training
Palo Alto Training
Adobe Analytics Training
Hey if we want to read record from column number 3 in excel what will be the change.
ReplyDeleteHow to get response back from apex to excel I performing Database.upsert functionality if there any error Database.error is capturing and it displaying in debug log but i want to get thos errr in aura component how can i Do that ? I want get response back from server after exection completed in Lighting component
ReplyDeleteCould you please provide the test class? @krishna kulkarni
ReplyDelete