+ Start a Discussion
aam1raam1r 

Date processing in Lightning Datatable

Hi Everyone,

I'm passing a salesforce record that includes date fields to a Lightning compnent's helper class.  The page renders a Lightning datatable and displays the results as expected.  However, the page loads and runs very slow.  Looking at the console logs i can see a huge count of warnings, which i believe is the culprit.  The message that pops up for these logs is as follows:

"<lightning-formatted-date-time> The value attribute accepts either a Date object, a timestamp, or a valid ISO8601 formatted string with timezone offset. but we are getting the object value "Invalid Date" instead."

The Helper class defines the columns and teh formatting as:
{label: 'Ordered Date',     fieldName: 'Ordered_Date__c',           type: 'date', typeAttributes:{year: 'numeric', month:'numeric',day:'numeric'} }
The component utilises the datatable and renders the data correctly but very slow.  Here is the use of the datatable:
<lightning:datatable aura:id="datatable" data="{! v.data }" columns="{! v.columns }" >
The v.data receives the List<Object> from apex and the v.columns is defined in the helper.js class.

I'm guessing it's some issue with how JS and Apex communicate dates but i'm very new to JS so cannot figure out what the issue could be.  Very sorry if teh question is not detailed abundantly.  If someone can give some guidance it would be great, as i really want to rid this error.  It takes too long to load the page with anything more than a a hundred records.

Thanks
Aamir
Dushyant SonwarDushyant Sonwar
Aamir,

Please post your lightning component code so that we can suggest you to improve performancee.

Also a screenshot of your console.logs to understand what warnings you are gettting
Naveen KNNaveen KN
Regarding the performance issue, datatable base component in the Aura framework takes more time to load the records compared to LWC (I have verified sometime ago to check the performance and I found LWC saves 'X' sec, depending on the data). If possible, convert your component to LWC and check the performance. 

and above I see that data table syntax is Aura and lightning formated date time in lwc tag. Am I missing something?
aam1raam1r
Thanks for getting back to me @Dushyant and @Neveen.  Naveen the date formatting was just me testing somethings.  Here are extracts of the code to better understand..
COMPONENT:
<aura:component controller="IGController" implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId" access="global">

    <lightning:workspaceAPI aura:id="workspace"/>

    <!-- attributes -->
    <aura:attribute name="excColumns" type="List" default="[]"/>
    <aura:attribute name="data" type="List" default="[]"/> 
    <aura:attribute name="rmdata" type="List" default="[]"/> 
    <aura:attribute name="dataTableSchema" type="Object"/>
    <aura:attribute name="keyField" type="String" default="id"/>
    <aura:attribute name="initialRows" type="Integer" default="5"/>
    <aura:attribute name="selectedRowsCount" type="Integer" default="0"/>
    
    <aura:attribute name="btDate" type="String" />    
    <aura:attribute name="dDate" type="String" />   
    <aura:attribute name="aCount" type="Integer"/>

    <aura:attribute name="apexController" type="igController"/>

    <!-- handlers-->
    <aura:handler name="init" value="{! this }" action="{! c.init }"/> <!-- When the component initialises -->

    <lightning:tabset selectedTabId="FI">

        <lightning:tab label="Excluded Products" id="EP">
            <!-- Loading Spinner--> 
            <lightning:spinner variant="brand" size="large" aura:id="Id_spinner" class="slds-hide" />
            <div class="slds-is-relative">
                <div class="c-container">
                    <lightning:layout >
                        <lightning:layoutItem padding="around-small">
                            <div class="header-column">
                                <p class="field-title" title="Bill To Date">Bill To Date</p>
                                <p>{! v.btDate }</p>
                            </div>
                        </lightning:layoutItem>
                        <lightning:layoutItem padding="around-small">
                            <div class="header-column">
                                <p class="field-title" title="Invoice Due Date">Invoice Due Date</p>
                                <p>{! v.dDate }</p>
                            </div>
                        </lightning:layoutItem>
                        <lightning:layoutItem padding="around-small">
                            <div class="header-column">
                                <p class="field-title" title="Number of Products">Number of Products</p>
                                <p>{! v.rmdata.length }</p>
                            </div>
                        </lightning:layoutItem>
                    </lightning:layout>
                </div>
        
                <!-- the container element determine the height of the datatable -->
                <div style="height: 700px">
                    <lightning:datatable aura:id="datatable" data="{! v.rmdata }" columns="{! v.excColumns }" keyField="{! v.keyField }" showRowNumberColumn="false" hideCheckboxColumn="true"/>
                </div>
            </div>
            
        </lightning:tab>
    </lightning:tabset>    
</aura:component>
CONTROLLER.JS
({
    
    init: function(cmp, event, helper) {

        console.log('init');

        var workspaceAPI = cmp.find("workspace");
        var tabId = '';
        
        workspaceAPI.getEnclosingTabId().then(function(t) {
            console.log('tabId');
            console.log(t);
            tabId = t;
        })

        .then(function(tab) {
            //console.log(tabId)
            workspaceAPI.setTabLabel({tabId:tabId, label:'IG'});
            workspaceAPI.setTabIcon({tabId:tabId, icon:'utility:pricing_workspace', iconAlt:'IG'});
        })
        
        .catch(function(error) {
            console.log('Error Setting tab id...')
            console.log(error);
        });

        cmp.set('v.excColumns',    helper.getExcludeColumnDefinitions()); // fieldName value needs to match API Name of field exactly
        
        helper.fetchDataWrap(cmp, event);

    },  


    updateSelectedText: function (cmp, event) {
        var selectedRows = event.getParam('selectedRows');
        cmp.set('v.selectedRowsCount', selectedRows.length);
    }  // END updateSelectedText


})
HELPER.JS
({
    getExcludeColumnDefinitions: function () {
        
        var columns = [
            
            {label: 'Opportunity',      fieldName: 'OppLink',       type: 'url', initialWidth: 200,  typeAttributes: { label: { fieldName: 'Opportunity_Name__c' }, target: '_self'} },
            {label: 'Br Date',          fieldName: 'OppBRDate',     type: 'date' }, 
            {label: 'Close Date',       fieldName: 'OppCloseDate',  type: 'date' },
            {label: 'Product Name',     fieldName: 'ProdLink',      type: 'url', initialWidth: 200,  typeAttributes: { label: { fieldName: 'Product_Name__c' }, target: '_self'} },
            {label: 'Status',           fieldName: 'Status__c',     type: 'text',  initialWidth: 100 },
            {label: 'Notes',            fieldName: 'Notes__c',      type: 'text' }

        ];

        return columns;
    },

    fetchDataWrap: function (cmp, event) { ///fetchData, numberOfRecords
        var apex = cmp.get('c.getInitProductList');
        var spinner = cmp.find('Id_spinner');

        $A.util.removeClass(spinner,'slds-hide');

        apex.setCallback(this, function (response) {
            
            $A.util.addClass(spinner,'slds-hide');
            
            var state = response.getState();
            var rtn = response.getReturnValue();    // return from Apex
            
            var map 			= rtn.mapOppsLineItems;
            var len 			= Object.keys(map).length;
            var removedList     = rtn.lstLineItemsRemoved;

            removedList.forEach(function(removedList) {
                removedList.OppLink         = "/" + removedList.OpportunityId,
                removedList.ProdLink        = "/" + removedList.Id,
                removedList.OppBRDate  = removedList.Opportunity.BR_Date__c,
                removedList.OppCloseDate    = removedList.Opportunity.CloseDate
            }); // */
            
            console.log('Return Data (fetchDataWrap)');
            console.log(rtn);
            
            if (state === "SUCCESS") {
                cmp.set('v.rmdata', rtn.lstLineItemsRemoved);
                cmp.set('v.btDate', rtn.endMonth);
                cmp.set('v.dDate',  rtn.idDate);
                cmp.set('v.aCount', len);
            } else {
                var errors = response.getError();
                console.error(errors);
            }
        });
        $A.enqueueAction(apex);
    },

  });
APEX CONTROLLER
public class igController {
    
    Integer daysInYear;

    Public Class firstInvoiceWrapper {
        
        @AuraEnabled
        Public String message {get;set;}
        
        @AuraEnabled
        Public Boolean isSuccess {get;set;}

        @AuraEnabled
        public Date endMonth {get;set;}

        @AuraEnabled
        public Date idDate {get;set;}
        
        @AuraEnabled
        Public Map<String, List<OpportunityLineItem> > mapOppsLineItems {get;set;}
        
        @AuraEnabled
        Public List<OpportunityLineItem> lstLineItems {get;set;}

        @AuraEnabled
        Public List<OpportunityLineItem> lstLineItemsRemoved {get;set;}
        
        Public firstInvoiceWrapper( String message, Boolean isSuccess, Date endMonth, Date idDate, 
            Map<String, List<OpportunityLineItem> > mapOppsLineItems, List<OpportunityLineItem> lstLineItemsRemoved ){
            
            this.message   	    = message;
            this.isSuccess 	    = isSuccess;
            this.endMonth = endMonth;
            this.idDate = idDate;
            
            this.mapOppsLineItems    = mapOppsLineItems;
            this.lstLineItemsRemoved = lstLineItemsRemoved;
        }
    }
    
    
    public igController() {
        Date today = Date.today();
        if (Date.isLeapYear(today.year())) {
            daysInYear = 366;
        }
        else { 
            daysInYear = 365;
        }
    }
    

    @AuraEnabled
    public static firstInvoiceWrapper getInitProductList(){

        List<Opportunity> lstOpps               = new List<Opportunity>();
        Map<String, List<OpportunityLineItem>>  mapOppsLineItems = new Map<String, List<OpportunityLineItem>>();
        List<OpportunityLineItem> lstLineItemsRemoved            = new List<OpportunityLineItem>();

        // Set Dates
        Date endOfThisMonth;
        Date idDate;
        
        // BT Date
        Date today = Date.today();
        endOfThisMonth = Date.parse( today.addMonths(1).toStartOfMonth().addDays(-1).format() );    // Date
        //endOfThisMonth = today.addMonths(1).toStartOfMonth().addDays(-1).format();        // String
        
        // iDate
        Datetime now = (Datetime)today;
        Integer daysToAdd = (now.format('E') == 'Sat') ? 13 : 12 - Integer.valueOf(now.format('u'));
        idDate = Date.parse( Date.newInstance(today.year(), today.month(), today.day() + daysToAdd).format() ); // Date


        // Fetch the Opp and Products marked as First Invoice Required
        try {
            lstOpps = [SELECT Id, 
                            (SELECT Opportunity_Name__c, Product_Name__c, Supplier__r.Name, Status__c, Cost_Price__c,
                                Opportunity.BR_Date__c, Opportunity.CloseDate,
                                Opportunity.AccountId, // for BP Number Link
                                Notes__c // for holding reason for exclusion - not written
                            FROM OpportunityLineItems
                            WHERE Collection_Frequency__c != 'Call Off')
                        FROM Opportunity WHERE CloseDate <= :Date.Today()]; // 
            
            // Build Map for query results
            for (Opportunity o : lstOpps) {
                for (OpportunityLineItem oli : o.OpportunityLineItems){
                    if (mapOppsLineItems.containsKey(o.Id)) {
                        mapOppsLineItems.get(o.Id).add(oli);    // add product to the same Opp
                    } else {
                        mapOppsLineItems.put(o.Id, new OpportunityLineItem[] { oli } );  // add the first Opp and product
                    }
                }       
                lstLineItemsRemoved.add(oli);         
            }


            firstInvoiceWrapper rtn = new firstInvoiceWrapper( 'SUCCESS', true, endOfThisMonth, idDate, mapOppsLineItems, lstLineItemsRemoved );
            return rtn;
            
        } catch (Exception e) {
            throw new AuraHandledException(e.getMessage());
        }
    }
}

Please bear in mind this is work in porgress and at present i'm trying to solve why i get a large numbr of console logging around "lightning-formatted-date-time".  The numbers in thsi screenshot are in dev.  when live in prod it goes into 1000s which haults the application for some time..
Console Log 1
Expanded:
Console Log 2
Any help is greatly appreciated.
Aamir
aam1raam1r
Ok, i found a fix.  The date values i'm passing in from apex to the component is not in an acceptable format according to https://developer.salesforce.com/docs/component-library/bundle/lightning:formattedDateTime/example

In order to get access to the individual formatting options on the component i switched over to a custom table with iteration instead of lightning datatable.  Initially i faced the same performance issue and warnings as before when using:
<td> <div class="slds-truncate" title="Close Date"><lightning:formattedDateTime value="{!product.Opportunity.CloseDate}" year="numeric" month="numeric" day="numeric"/></div> </td>
But then i switched to the following and it it resolved the issue:
<td> <div class="slds-truncate" title="Close Date"><ui:outputDate value="{!product.Opportunity.CloseDate}" format="dd/MM/yyyy"/></div> </td>
And i applied the same to every date field to completely remove the warnings i was getting.
I'll still love to know how to get around this using the lightning datatable.  But for now, i'm happy this is resolved.  Thanks to whoever tried looking in to this.
Aamir