0

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'/>
                                     &nbsp; &nbsp; &nbsp;   
                                     <lightning:button label="Previous" disabled="{!v.currentPage == 0}"  
                                       onclick="{!c.previous}" variant="brand"
                                       iconName='utility:back'/>
                                     &nbsp; &nbsp; &nbsp;
                                     <button class="slds-button slds-button--neutral">
                                     {!v.currentPage} / {!v.totalPages}
                                     </button>
                                     &nbsp; &nbsp; &nbsp;
                                     <lightning:button label="Next" disabled="{!v.currentPage >= v.totalPages}" 
                                       onclick="{!c.next}" variant="brand"
                                     iconName='utility:forward' iconPosition='right'/>
                                     &nbsp; &nbsp; &nbsp;
                                     <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;
    }
3

I see that you are invoking getPicklistOptions 4 times and passing loadOrder as true in 4th call believing it will be invoked last - which is not true. All the calls will be sent together and returned together due to concept called boxcar’ing - so it does not matter whichever method has it as true.

You have below options to improve . (you can implement either 1 or all options)

Option 1: Make the long running call hlp.getPicklistOptions(cmp, 'OrderItem', 'Prod_Code__c',false); backgrounded

getPicklistOptions: function (cmp, objectName, fieldName, loadOrder, background) {
    var self = this;
    var action = cmp.get('c.getOptions');
    if(background) action.setBackground();
    // other logic

and in controller:

hlp.getPicklistOptions(cmp, 'OrderItem', 'Prod_Code__c',false, true);

For required method, you can pass background as true. In this case, as this is long running call, the action will be enqueued separately not affecting main call and anything dependent on this will be processed after getting response from apex - do not pass loadOrder as true for this method.

The other option might not improve performance but you can try

Option 2: Instead of invoking it 4 times, you can get all picklist options in single transaction (from apex processing point of view) by using the apex method shown in Dynamic Picklist Value Retrieval. Note that instead of passing single picklist each time, you can pass all of them together and you will get a Map in response which will have picklist field name as key to its options as values

1
  • Sas thanks for the suggestions and I can see how these would help the initial load of the component and will give them a shot. But am not sure how this would help the next button to render the next set of lines faster since its just grabbing values from the orderlines attribute. Commenting out the getPicklistOptions line just helps because the component doesn't have to load all of the values for the product code field – Guest Sep 11 '19 at 14:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.