Infinite Loading of Data Table in Lightning Web Component

In Lightning Web component, we can develop Lightning data table with infinite loading capability. This will help users to see more records whenever they scroll to the bottom of the table rows, querying more every time the user scrolls to the end rather than querying all records at once.

In Lightning Web component, we can develop Lightning data table with infinite loading capability. This will help users to see more records whenever they scroll to the bottom of the table rows, querying more every time the user scrolls to the end rather than querying all records at once. This will also replace pagination where users must click next/previous button to see more records.  

Cons of Using Pagination: 

  • Requires writing up complex lines of code 
  • Need to develop buttons for next, previous, first page and last page and alignment of these elements 
  • Need to develop events and functions for each of the above buttons 
  • Users need to click each button every time they need to navigate 

Features: 

  • Faster load performance due to a smaller number of records are loaded for each scroll event 
  • Loading spinner at the end of the table to indicate records are being fetched. 
  • Toast messages on exceptions and when all records are loaded. 
  • Displaying record count for each scroll event, respectively. 
  • Fetches records from server every time (every load more). 

Common issues faced during development: 

  • Scroll event getting called multiple times for a single end scroll 
  • Scroll event getting called along with the constructor on Page load resulting in 2X initial rows 
  • ‘Load more’ results being concatenated incorrectly or duplicated results 

The following code will resolve the above known issues that occurs more often,  

The HTML Code (InfiniteTable.html) 

  1. <template>?? 
  2. ????<lightning-card>?? 
  3. ????????<h3?slot=“title”>?? 
  4. ????????????<lightning-icon?icon-name=“utility:user”?size=“small”></lightning-icon>?? 
  5. ??????????????Infinite?Loading?Account?List?? 
  6. ????????????<div?style=“float:right”>?? 
  7. ????????????????<template?if:true={disableLoadMore}>?? 
  8. ????????????????????Showing?All?? 
  9. ????????????????</template>?? 
  10. ????????????????<template?if:false={disableLoadMore}>?? 
  11. ????????????????????Showing?{currentCount}?of?{totalRecordCount}?? 
  12. ????????????????</template>?? 
  13. ????????????</div>?? 
  14. ????????</h3>?? 
  15. ????????<div?style=“height:310px”>?? 
  16. ????????<!–Lightning?data?table?markup–>?? 
  17. ????????????<lightning-datatable?? 
  18. ????????????????data={accountData}?? 
  19. ????????????????columns={accountColumns}?? 
  20. ????????????????key-field=“Id”?? 
  21. ????????????????hide-checkbox-column?? 
  22. ????????????????show-row-number-column?? 
  23. ????????????????enable-infinite-loading?? 
  24. ????????????????onloadmore={handleLoadMore}?? 
  25. ????????????>?? 
  26. ????????????</lightning-datatable>?? 
  27. ????????</div>?? 
  28. ????????<div?slot=“footer”>?? 
  29. ????????????{loadMoreStatus}?{error}?? 
  30. ????????</div>?? 
  31. ????</lightning-card>?? 
  32. </template>?? 

JavaScript (InfiniteTable.js) 

  1. import?{?LightningElement,?track?}?from?lwc;?? 
  2. import?fetchAccountRecords?from?‘@salesforce/apex/InfiniteTableController_AC.fetchAccountRecords’;?? 
  3. import?{?ShowToastEvent?}?from?‘lightning/platformShowToastEvent’;?? 
  4. ?? 
  5. export?default?class?InfinteTable?extends?LightningElement?{?? 
  6. ????@track?_accountData?=?[];?? 
  7. ????@track?error;?? 
  8. ????@track?loadMoreStatus?=?;?? 
  9. ????queryOffset;?? 
  10. ????currentCount?=?0;?? 
  11. ????queryLimit;?? 
  12. ????totalRecordCount;?? 
  13. ????timesCalled?=?0;?? 
  14. ????disableLoadMore?=?false;?? 
  15. ????fromConstructor;?? 
  16. ????@track?accountColumns?=?[{?? 
  17. ????????????label?????:?“Account?Name”,?? 
  18. ????????????fieldName?:?“Name”,?? 
  19. ????????????type??????:?“text”?? 
  20. ????????},?{?? 
  21. ????????????label?????:?“Rating”,?? 
  22. ????????????fieldName?:?“Rating”,?? 
  23. ????????????type??????:?“text”?? 
  24. ????????},?{?? 
  25. ????????????label?????:?“Account?Source”,?? 
  26. ????????????fieldName?:?AccountSource,?? 
  27. ????????????type??????:?“text”?? 
  28. ????????},?{?? 
  29. ????????????label?????:?“Created?By”,?? 
  30. ????????????fieldName?:?CreatedByName,?? 
  31. ????????????type??????:?“text”?? 
  32. ????????},?{?? 
  33. ????????????label?????:?“Created?Date”,?? 
  34. ????????????fieldName?:?“CreatedDate”,?? 
  35. ????????????type??????:?“date”,?? 
  36. ????????????typeAttributes?:?{?? 
  37. ????????????????year:?“numeric”,?? 
  38. ????????????????month:?“long”,?? 
  39. ????????????????day:?“2-digit”,?? 
  40. ????????????????hour:?“2-digit”,?? 
  41. ????????????????minute:?“2-digit”?? 
  42. ????????????}?? 
  43. ????????}?? 
  44. ????];?? 
  45. ?? 
  46. ????constructor()?{?? 
  47. ????????super();?? 
  48. ????????this.queryOffset?=?0;?? 
  49. ????????this.queryLimit?=?10;?? 
  50. ????????this.fromConstructor?=?true;?? 
  51. ????????this.fetchRecords();?? 
  52. ????????this.currentCount?=?10;?? 
  53. ????????console.log(‘Called?from?Infinite?Table?Constructor?’+this.queryOffset);?? 
  54. ????}?? 
  55. ?? 
  56. ????showToast(type,?title,?message,?variant,?mode)?{?? 
  57. ????????const?evt?=?new?ShowToastEvent({?? 
  58. ????????????type?:?type,?? 
  59. ????????????title:?title,?? 
  60. ????????????message:?message,?? 
  61. ????????????variant:?variant,?? 
  62. ????????????mode:?mode?? 
  63. ????????});?? 
  64. ????????this.dispatchEvent(evt);?? 
  65. ????}?? 
  66. ?? 
  67. ????handleLoadMore(event)?{?? 
  68. ????????if(this.disableLoadMore)?? 
  69. ????????????return;?? 
  70. ????????if(this.fromConstructor?==?true)?{?? 
  71. ????????????this.fromConstructor?=?false;?? 
  72. ????????????return;?? 
  73. ????????}?? 
  74. ????????const?{?target?}?=?event;?? 
  75. ????????//Display?a?spinner?to?signal?that?data?is?being?loaded?? 
  76. ????????target.isLoading?=?true;?? 
  77. ????????if(this.totalRecordCount?>?this.queryOffset)?{?? 
  78. ????????????this.queryOffset?=?this.queryOffset?+?10;?? 
  79. ????????????this.fetchRecords()?? 
  80. ????????????.then(()=>?{?? 
  81. ????????????????target.isLoading?=?false;?? 
  82. ????????????????if(this.totalRecordCount?>?(this.currentCount?+?10))?? 
  83. ????????????????????this.currentCount?=?this.currentCount?+?10;?? 
  84. ????????????????else?? 
  85. ????????????????????this.currentCount?=?this.totalRecordCount;?? 
  86. ????????????});?? 
  87. ????????}?? 
  88. ????????else?{?? 
  89. ????????????target.isLoading?=?false;?? 
  90. ????????????this.disableLoadMore?=?true;?? 
  91. ????????????this.loadMoreStatus?=?‘No?more?to?load.’;?? 
  92. ????????????this.showToast(‘Success’,?‘Success’,?‘All?Account?Records?are?Loaded!’,?‘success’,?‘dismissible’);?? 
  93. ????????}?? 
  94. ????????console.log(‘Called?from?Infinite?Table?Handle?More?’+this.queryOffset);?? 
  95. ????}?? 
  96. ?? 
  97. ????fetchRecords()?{?? 
  98. ????????let?newData;?? 
  99. ????????return?fetchAccountRecords({?? 
  100. ????????????queryLimit?:?this.queryLimit,??? 
  101. ????????????queryOffset😕this.queryOffset?? 
  102. ????????})?? 
  103. ????????.then(result?=>?{??? 
  104. ????????????this.totalRecordCount?=?result.totalRecordCount;?? 
  105. ????????????newData?=?JSON.parse(JSON.stringify(result.accRecords));?? 
  106. ????????????newData.forEach(function(entry)?{?? 
  107. ????????????????//?flatten?the?data?to?that?it?can?be?directly?consumed?by?data?table?? 
  108. ????????????????if?(entry.CreatedBy){?? 
  109. ????????????????????entry.CreatedByName?=?entry.CreatedBy.Name;?? 
  110. ????????????????}?? 
  111. ????????????});?? 
  112. ????????????let?newRecords?=?[…this._accountData,?…newData];?? 
  113. ????????????this._accountData?=?newRecords;?? 
  114. ????????????this.error?=?undefined;?? 
  115. ????????})?? 
  116. ????????.catch(error?=>?{??? 
  117. ????????????this.error?=?error;?? 
  118. ????????????this.showToast(‘Error’,?‘Error’,?‘Error?getting?records?from?Server’,?‘error’,?‘sticky’);?? 
  119. ????????})?? 
  120. ????}?? 
  121. ?? 
  122. ????get?accountData()?{?? 
  123. ????????return?this._accountData.length???this._accountData?:?null;?? 
  124. ????}?? 
  125. }?? 

Apex Controller (InfiniteTableController_AC.cls) 

  1. public?with?sharing?class?InfiniteTableController_AC?{?? 
  2. ?? 
  3. ????@AuraEnabled(cacheable?=?true)?? 
  4. ????public?static?AccountWrapper?fetchAccountRecords(Integer?queryLimit,?Integer?queryOffset)?{?? 
  5. ????????return?new?AccountWrapper([SELECT?count()?FROM?Account],?? 
  6. ????????[SELECT?Name,?CreatedBy.Name,?Rating,?AccountSource,?CreatedDate??? 
  7. ????????????????FROM?Account?? 
  8. ????????????????ORDER?BY?CreatedDate?DESC??? 
  9. ????????????????LIMIT?:queryLimit??? 
  10. ????????????????OFFSET?:queryOffset]);?? 
  11. ????}?? 
  12. ?? 
  13. ????public?class?AccountWrapper?{?? 
  14. ????????@AuraEnabled?? 
  15. ????????public?Integer?totalRecordCount?{?get;?set;?}?? 
  16. ????????@AuraEnabled?? 
  17. ????????public?List<Account>?accRecords?{?get;?set;?}?? 
  18. ????????public?AccountWrapper(Integer?totalRecordCount,?List<Account>?accRecords)?{?? 
  19. ????????????this.totalRecordCount?=?totalRecordCount;?? 
  20. ????????????this.accRecords?=?accRecords;?? 
  21. ????????}?? 
  22. ????}?? 
  23. }?? 

Output: 

When Page Loads, 

 

When all records are scrolled and loaded, 

 

Conclusion: 

The Infinite Loading data table can reduce a lot of manual code that we used to build for Tables with Paginations. Combining with LWC, the table view development can work faster. 

About MST

At MST Solutions our cornerstone is to adapt, engage and create solutions which guarantee the success of our clients. The talent of our team and experiences in varied business verticals gives us an advantage over other competitors.

Recent Articles

Work with us.

Our people aren’t just employees, they are key to the success of our business. We recognize the strengths of each individual and allow them time and resources to further develop those skills, crafting a culture of leaders who are passionate about where they are going within our organization.