Hey having some performance issues with pagination in a lightning component. The actual functionality works correctly the problem I am noticing is its slow to change pages. From what I can tell the main issue is the product code pick list. This is just a sample of the code but when I comment out this line "hlp.getPicklistOptions(cmp, 'OrderItem', 'Prod_Code__c',false);" the component loads 3ish seconds faster. We have roughly 60-100 product codes that this retrieves from the server on init. A kick in the direction on how to make this perform better would be greatly appreciated.
Comp
<aura:component description="OrderLineItems"
implements="lightning:isUrlAddressable,flexipage:availableForRecordHome,force:lightningQuickActionWithoutHeader,force:hasRecordId"
controller="OrderItemController"
access="global">
<aura:attribute name="recordId" type="String" access="global"/>
<aura:attribute name="order" type="Order"/>
<aura:attribute name="orderLines" type="OrderItem[]"/>
<aura:attribute name="allDrawers" type="Boolean" default="false"/>
<aura:attribute name="picklistOptions" type="Object"/>
<aura:attribute name="loaded" type="Boolean" default="false"/>
<aura:attribute name="PaginationList" type="OrderItem[]"/>
<aura:attribute name="startPage" type="Integer" />
<aura:attribute name="endPage" type="Integer"/>
<aura:attribute name="totalRecords" type="Integer"/>
<aura:attribute name="totalPages" type="Integer" />
<aura:attribute name="currentPage" type="Integer" default="0"/>
<aura:attribute name="pageSize" type="Integer" default="10"/>
<aura:handler name="init" value="{!this}" action="{!c.init}"/>
<aura:handler name="change" value="{!v.pageReference}" action="{!c.init}"/>
<lightning:notificationsLibrary aura:id="notifLib"/>
<aura:if isTrue="{!!v.loaded}">
<lightning:spinner alternativeText="Loading" size="large"/>
</aura:if>
<aura:if isTrue="{!v.loaded}">
<aura:if isTrue="{!v.PaginationList.length}">
<lightning:layout horizontalAlign="spread" verticalAlign="start" multipleRows="true">
<lightning:layoutItem class="slds-m-bottom--small" size="12">
<aura:if isTrue="{!v.IFSSuccess}">
<div class="slds-notify slds-notify_alert slds-theme_alert-texture slds-theme_info slds-text-align--left"
role="alert">
<h2 style="white-space: pre-line;">{!v.IFSMessage}</h2>
</div>
</aura:if>
<div class="slds-table_edit_container slds-page-header" style="background-color: white; width:1575px">
<table border="0"
class="slds-table slds-no-row-hover slds-table_fixed-layout editform"
role="grid">
<aura:if isTrue="{!greaterthan(v.orderLines.length,v.pageSize) }">
<div class="slds-align_absolute-center">
<lightning:buttonGroup >
<lightning:button label="First" disabled="{!v.currentPage == 0}"
onclick="{!c.firstpage}" variant="brand"
iconName='utility:left'/>
<lightning:button label="Previous" disabled="{!v.currentPage == 0}"
onclick="{!c.previous}" variant="brand"
iconName='utility:back'/>
<button class="slds-button slds-button--neutral">
{!v.currentPage} / {!v.totalPages}
</button>
<lightning:button label="Next" disabled="{!v.currentPage >= v.totalPages}"
onclick="{!c.next}" variant="brand"
iconName='utility:forward' iconPosition='right'/>
<lightning:button label="Last" disabled="{!v.currentPage == v.totalPages}"
onclick="{!c.lastpage}" variant="brand"
iconName='utility:right' iconPosition='right'/>
</lightning:buttonGroup>
</div>
</aura:if>
<aura:iteration items="{!v.PaginationList}" var="oi" indexVar="oiIndex">
<lightning:recordEditForm recordId="{!oi.Id}" objectApiName="OrderItem" class="editform">
<lightning:layoutItem class="editform">
<aura:if isTrue="{!oiIndex == (0)}">
<tr style="border-bottom: 1px solid black;">
<td class="line-number label">Line #</td>
<td class="quantity label">Qty</td>
<td class="use-partnum label">Use Part#</td>
<td class="ifs-part-number label">Manufacturer Part #</td>
<td class="ifs-part-number label">IFS Part #</td>
<td class="description label">Part Desc.</td>
<td class="cost label">Cost</td>
<td class="sell label">Sell</td>
<td class="margin-h label">Margin %</td>
<td class="supply-code-h label">Supply Code</td>
<td class="promise-date label">Promise Date</td>
<td class="drawer">
<lightning:buttonIcon name="all-drawers" iconName="utility:down" size="x-small"
alternativeText="Expand all items" onclick="{!c.openDrawer}"/>
</td>
</tr>
</aura:if>
</lightning:layoutItem>
<tr>
<td class="slds-cell-wrap line-number">
<lightning:input label="CustLine__c" variant="label-hidden" type="text"
value="{!oi.CustLine__c}"/>
</td>
<td class="slds-cell-wrap quantity">
<lightning:input label="Quantity" variant="label-hidden" type="number"
value="{!oi.Quantity}"/>
</td>
<td class="slds-cell-wrap use-partnum">
<lightning:input name="{!oi.Id}" aura:id="to-part" type="checkbox"
label="Use as Part Number" variant="label-hidden"
checked="{!oi.Assign_Part__c}" onchange="{!c.updateToPart}"/>
</td>
<td class="slds-cell-wrap ifs-part-number">
<lightning:input label="Part Number" variant="label-hidden" type="text"
value="{!oi.Part_Number_CPQ__c}"/>
</td>
<td class="slds-cell-wrap ifs-part-number">
<ui:outputText value="{!oi.Inventory_Part_Number_IFS__c}"/>
</td>
<td class="slds-cell-wrap description">
<lightning:input label="Description" variant="label-hidden"
value="{!oi.Line_Description__c}" type="text"/>
</td>
<td class="slds-cell-wrap cost">
<ui:inputCurrency value="{!oi.Unit_Cost__c}"/>
</td>
<td class="slds-cell-wrap sell">
<ui:inputCurrency value="{!oi.UnitPrice}"/>
</td>
<td class="slds-cell-wrap margin">
<ui:outputNumber value="{!oi.Margin__c}" format="0.00%"/>
</td>
<td class="slds-cell-wrap supply-code">
<lightning:select name="supply-code" label="" value="{!oi.Supply_Code__c}" class="supply-code">
<option value="">None</option>
<aura:iteration items="{!v.picklistOptions.Supply_Code__c}" var="op">
<option value="{!op.value}">{!op.label}</option>
</aura:iteration>
</lightning:select>
</td>
<td class="slds-cell-wrap promise-date">
<c:CustomDateField dateValue="{!oi.Promise_Date__c}" />
</td>
<td class="slds-text-align--right drawer">
<lightning:buttonIcon name="{!oi.Id}" iconName="utility:down" size="x-small"
alternativeText="Expand item" onclick="{!c.openDrawer}"/>
</td>
</tr>
<tr>
<td colspan="2" class="slds-cell-wrap leadtime">
<label>Lead Time</label>
<lightning:input label="Lead Time" variant="label-hidden" type="text"
value="{!oi.Lead_Time__c}"/>
</td>
<td class="slds-cell-wrap">
<label>Qty Avail.</label><br/>
<ui:outputNumber value="{!oi.Available_Qty_num__c}"/>
</td>
<td colspan="2" class="slds-cell-wrap">
<label>Transaction ID</label>
<lightning:inputField variant="label-hidden" fieldName="Transaction_ID__c"
value="{!oi.Transaction_ID__c}" class="transaction-id" />
</td>
<td colspan="2" class="slds-cell-wrap supplier">
<label>Supplier</label><br/>
<lightning:inputField variant="label-hidden" fieldName="Supplier__c" value="{!oi.Supplier__c}" class="supplier"/>
</td>
<td colspan="2" class="slds-cell-wrap">
<label>Product Code</label>
<lightning:select name="product-code" label="" value="{!oi.Prod_Code__c}"
class="product-code">
<option value="">None</option>
<aura:iteration items="{!v.picklistOptions.Prod_Code__c}" var="op">
<option value="{!op.value}">{!op.label}</option>
</aura:iteration>
</lightning:select>
</td>
<td class="slds-cell-wrap">
<label>Part Type</label>
<lightning:select name="part-type" label="" value="{!oi.Type_Code__c}"
class="part-type">
<option value="">None</option>
<aura:iteration items="{!v.picklistOptions.Type_Code__c}" var="op">
<option value="{!op.value}">{!op.label}</option>
</aura:iteration>
</lightning:select>
</td>
<td class="slds-cell-wrap">
<label>Quote Type</label>
<lightning:select name="quote-type" label="" value="{!oi.Quote_Type__c}"
class="quote-type">
<option value="">None</option>
<aura:iteration items="{!v.picklistOptions.Quote_Type__c}" var="op">
<option value="{!op.value}">{!op.label}</option>
</aura:iteration>
</lightning:select>
</td>
</tr>
</lightning:recordEditForm>
</aura:iteration>
</table>
</div>
</lightning:layoutItem>
</lightning:layout>
</aura:if>
</aura:if>
</aura:component>
Cont
({
init: function (cmp, evt, hlp) {
cmp.set('v.order',null);
cmp.set('v.currentPage',0)
cmp.set('v.orderLines',[]);
cmp.set('v.PaginationList', []);
cmp.set('v.loaded', false);
var pageReference = cmp.get("v.pageReference");
if(pageReference){
console.log(pageReference.state.c__recordId);
cmp.set('v.recordId',pageReference.state.c__recordId);
}
else{
console.log(cmp.get('v.recordId'));
}
cmp.set('v.picklistOptions',{
'Quote_Type__c': []
});
hlp.getPicklistOptions(cmp, 'OrderItem', 'Quote_Type__c',false);
hlp.getPicklistOptions(cmp, 'OrderItem', 'Type_Code__c',false);
hlp.getPicklistOptions(cmp, 'OrderItem', 'Prod_Code__c',false);
hlp.getPicklistOptions(cmp, 'OrderItem', 'Supply_Code__c',true);
},
next: function (cmp,evt,hlp){
var pageNumber = cmp.get("v.currentPage");
cmp.set("v.currentPage", pageNumber+1);
hlp.next(cmp);
},
previous: function (cmp,evt,hlp) {
var pageNumber = cmp.get("v.currentPage");
cmp.set("v.currentPage", pageNumber-1);
hlp.previous(cmp);
},
firstpage: function (cmp,evt,hlp) {
cmp.set("v.currentPage", 0);
hlp.first(cmp);
},
lastpage: function (cmp,evt,hlp) {
var pageNumber = cmp.get("v.totalPages");
cmp.set("v.currentPage", pageNumber);
hlp.last(cmp);
}
Hlp
({
getPicklistOptions: function (cmp, objectName, fieldName, loadOrder) {
var self = this;
//console.log('getPicklistOptions',objectName,fieldName);
var action = cmp.get('c.getOptions');
action.setParams({
objectName: objectName,
picklistField: fieldName
});
action.setCallback(this, function (response) {
var state = response.getState();
if (state === 'SUCCESS') {
//handle success
var result = response.getReturnValue();
console.log(result);
var picklistOptions = cmp.get('v.picklistOptions');
picklistOptions[fieldName] = result;
cmp.set('v.picklistOptions',picklistOptions);
if(loadOrder){
console.log("loadOrder");
self.getOrder(cmp);
}
} else if (state === 'INCOMPLETE') {
//handle incomplete
} else if (state === 'ERROR') {
//handle error
var errors = response.getError();
if (errors) {
if (errors[0] && errors[0].message) {
console.log("Error message: " + errors[0].message);
}
} else {
console.log("Unknown error");
}
}
});
$A.enqueueAction(action);
},
getOrder: function(cmp){
console.log("GetOrder");
var self = this;
var pageReference = cmp.get("v.pageReference");
if(pageReference){
console.log(pageReference.state.c__recordId);
cmp.set('v.recordId',pageReference.state.c__recordId);
}
var recordId = cmp.get('v.recordId');
cmp.set('v.loaded',false);
cmp.set('v.currentPage',0)
cmp.set('v.PaginationList', []);
cmp.set('v.orderLines',[]);
cmp.set('v.totalPages',0);
cmp.set('v.totalPages',0);
var action = cmp.get('c.getOrder');
action.setParams({
orderId: recordId
});
action.setCallback(this, function (response) {
var state = response.getState();
console.log(response.getState());
if (state === 'SUCCESS') {
var result = response.getReturnValue();
cmp.set('v.order',result);
if(!$A.util.isEmpty(result.OrderItems)){
cmp.set('v.totalPages', Math.ceil(result.OrderItems.length/cmp.get('v.pageSize'))-1);
var pageSize = cmp.get("v.pageSize"); // 10 Records
cmp.set('v.orderLines', result.OrderItems);
cmp.set("v.totalRecords", cmp.get("v.orderLines").length);
// set star as 0
cmp.set("v.startPage",0);
cmp.set("v.endPage",pageSize-1);
var PaginationList = [];
for(var i=0; i< pageSize; i++){
console.log('i',i);
if(cmp.get("v.orderLines").length> i){
PaginationList.push(result.OrderItems[i]);
}
}
PaginationList.map(function (oi) {
oi.dateErrors = [{'message': 'Invalid date (mm/dd/yyyy)'}];
if(!oi.hasOwnProperty('Supplier__c')){
oi.Supplier__c = null;
}
if(!oi.hasOwnProperty('Transaction_ID__c')){
oi.Transaction_ID__c = null;
}
});
cmp.set('v.PaginationList', PaginationList);
}
else{
var orderLines = result.OrderItems;
cmp.set('v.PaginationList',[]);
}
} else if (state === 'INCOMPLETE') {
//handle incomplete
} else if (state === 'ERROR') {
//handle error
var errors = response.getError();
if (errors) {
if (errors[0] && errors[0].message) {
console.log("Error message: " + errors[0].message);
}
} else {
console.log("Unknown error");
}
}
cmp.set('v.loaded',true);
});
$A.enqueueAction(action);
},
next : function(cmp){
var sObjectList = cmp.get("v.orderLines");
var end = cmp.get("v.endPage");
var start = cmp.get("v.startPage");
var pageSize = cmp.get("v.pageSize");
var Paginationlist = [];
var counter = 0;
for(var i=end+1; i<end+pageSize+1; i++){
if(sObjectList.length > i){
Paginationlist.push(sObjectList[i]);
}
counter ++ ;
console.log('counter', counter);
}
start = start + counter;
end = end + counter;
console.log('start', start);
console.log('send', end);
cmp.set("v.startPage",start);
cmp.set("v.endPage",end);
cmp.set('v.PaginationList', Paginationlist);
},
previous : function(cmp){
var sObjectList = cmp.get("v.orderLines");
var end = cmp.get("v.endPage");
var start = cmp.get("v.startPage"); // 0
var pageSize = cmp.get("v.pageSize"); //10
var Paginationlist = [];
var counter = 0;
for(var i= start-pageSize; i < start ; i++){
if(i > -1){
Paginationlist.push(sObjectList[i]);
counter ++;
}else{
start++;
}
}
start = start - counter;
end = end - counter;
cmp.set("v.startPage",start);
cmp.set("v.endPage",end);
cmp.set('v.PaginationList', Paginationlist);
},
first: function(cmp){
var sObjectList = cmp.get("v.orderLines");
var end = cmp.get("v.endPage");
var start = cmp.get("v.startPage"); // 0
var pageSize = cmp.get("v.pageSize"); //10
var Paginationlist = [];
for(var i=0; i< pageSize-1; i++){
if(cmp.get("v.orderLines").length> i){
Paginationlist.push(sObjectList[i]);
}
}
cmp.set("v.startPage",0);
cmp.set("v.endPage",pageSize-1);
cmp.set('v.PaginationList', Paginationlist);
},
last: function(cmp){
var sObjectList = cmp.get("v.orderLines");
var totalrec = cmp.get("v.totalRecords");
var end = cmp.get("v.endPage");
var start = cmp.get("v.startPage"); // 0
var pageSize = cmp.get("v.pageSize"); //10
var Paginationlist = [];
for(var i=totalrec-pageSize; i< totalrec; i++){
if(cmp.get("v.orderLines").length> i){
Paginationlist.push(sObjectList[i]);
}
}
cmp.set("v.startPage",totalrec-pageSize);
cmp.set("v.endPage",totalrec);
cmp.set('v.PaginationList', Paginationlist);
}
});
Class Method
@AuraEnabled
public static PicklistOption[] getOptions(String objectName, String picklistField){
PicklistOption[] options = new PicklistOption[]{};
System.debug('objectName: ' + objectName);
System.debug('picklistField: ' + picklistField);
try{
DescribeSObjectResult objResult = Schema.getGlobalDescribe().get(objectName).getDescribe();
Schema.DescribeFieldResult fieldResult = objResult.fields.getMap().get(picklistField).getDescribe();
Schema.PicklistEntry[] ple = fieldResult.getPicklistValues();
for( Schema.PicklistEntry pickListVal : ple){
if(pickListVal.active){
PicklistOption po = new PicklistOption();
po.label = pickListVal.getLabel();
po.value = pickListVal.getValue();
options.add(po);
}
}
}
catch (Exception e){
System.debug('OrderItemController.getOptions: ' + e.getMessage());
throw new AuraHandledException(e.getMessage());
}
return options;
}