I got a lightning:datatable where I also have a search input field to search for whatever the user types in the input field. I can't get this to work together with an infinite scrolling table. Wonder if someone can help me out. If I have infinitescrolling enabled, the filter functionality does not work (I assume because the table keeps re-rendering when I type into the input field)
My markup:
<extends="c:Base" controller="AccountBrowserForm">
<aura:handler name="init" value="{! this }" action="{! c.doInit }"/>
<aura:attribute name="selectedAccountId" type="Id" access="public" />
<aura:attribute name="accounts" type="List"/>
<aura:attribute name="mycolumns" type="List"/>
<aura:attribute name="sortedBy" type="String" />
<aura:attribute name="sortedDirection" type="Boolean" default="true" />
<aura:attribute name="backingdata" type="List" /> <!-- backing data to allow a narrowed down datatable -->
<aura:attribute name="filter" type="String" /> <!-- filter input -->
<aura:registerEvent name="AccountFilterChange" type="c:AccountFilterChange" />
<aura:attribute name="enableInfiniteLoading" type="Boolean" default="true"/>
<aura:attribute name="initialRows" type="Integer" default="5"/>
<aura:attribute name="rowsToLoad" type="Integer" default="1"/>
<aura:attribute name="totalNumberOfRows" type="Integer" default="5"/>
<aura:attribute name="loadMoreStatus" type="String" default=""/>
<aura:attribute name="rowNumberOffset" type="Integer" default="0"/>
<aura:attribute name="currentCount" type="Integer" default="10"/>
<div class="forminput">
<lightning:input type="text"
onchange="{!c.filter}"
value="{!v.filter}"
placeholder="{!$Label.c.Searchfield_Placeholder}" />
</div>
<lightning:datatable aura:id="lightningTable"
data="{! v.accounts }"
columns="{! v.mycolumns }"
keyField="Id"
onrowaction="{! c.handleRowAction }"
onsort="{!c.updateColumnSorting}"
sortedBy="{!v.sortedBy}"
sortedDirection="{!v.sortedDirection}"
loadMoreOffset="{! v.loadMoreOffset }"
enableInfiniteLoading="{!v.enableInfiniteLoading}"
onloadmore="{! c.loadMoreData }"
hideCheckboxColumn="true"/>
{! v.loadMoreStatus }
Controller:
doInit: function (component, event, helper) {
helper.callServer(component, "c.getAccounts", $A.getCallback(function (response) {
component.set("v.accounts", response);
component.set("v.backingdata", response); // Need to fetch a copy because we use this when we filter the data.
component.set('v.mycolumns', [{
type: "button",
typeAttributes: {
label: '',
iconName: 'utility:add',
name: 'selectRecord',
title: 'selectRecord',
disabled: false,
value: 'edit',
variant: {
fieldName: 'variantValue'
},
}
},
{label: $A.get("$Label.c.Name"), fieldName: 'Name', type: 'text', sortable: true},
{label: $A.get("$Label.c.Street"), fieldName: 'BillingStreet', type: 'text', sortable: true},
{label: $A.get("$Label.c.Postal_Code"), fieldName: 'BillingPostalCode', type: 'text', sortable: true},
{label: $A.get("$Label.c.City"), fieldName: 'BillingCity', type: 'text', sortable: true},
{label: $A.get("$Label.c.Country"), fieldName: 'BillingCountry', type: 'text', sortable: true},
]);
}))
},
filter: function (component, event, helper) {
var data = component.get("v.backingdata"),
term = component.get("v.filter"),
results = data, regex;
try {
regex = new RegExp(term, "i");
// filter checks each row, constructs new array where function returns true
results = data.filter(row => regex.test(row.Name) ||
regex.test(row.BillingStreet) ||
regex.test(row.BillingPostalCode.toString()) ||
regex.test(row.BillingCity) ||
regex.test(row.BillingCountry));
}
catch (e) {
// invalid regex, use full list
}
component.set("v.accounts", results);
},
loadMoreData: function (cmp, event, helper) {
//Display a spinner to signal that data is being loaded
event.getSource().set("v.isLoading", true);
//Display "Loading" when more data is being loaded
cmp.set('v.loadMoreStatus', 'Loading');
helper.fetchData(cmp, cmp.get('v.rowsToLoad'))
.then($A.getCallback(function (data) {
if (cmp.get('v.accounts').length >= cmp.get('v.totalNumberOfRows')) {
cmp.set('v.enableInfiniteLoading', false);
cmp.set('v.loadMoreStatus', 'No more data to load');
} else {
var currentData = cmp.get('v.accounts');
//Appends new data to the end of the table
var newData = currentData.concat(data);
cmp.set('v.accounts', newData);
cmp.set('v.loadMoreStatus', '');
}
event.getSource().set("v.isLoading", false);
}));
}
Helper
fetchData: function(component , rows){
return new Promise($A.getCallback(function(resolve, reject) {
var currentDatatemp = component.get('c.getAccounts');
var counts = component.get("v.currentCount");
currentDatatemp.setCallback(this, function(a) {
resolve(a.getReturnValue());
var countstemps = component.get("v.currentCount");
countstemps = countstemps+component.get("v.initialRows");
component.set("v.currentCount",countstemps);
});
$A.enqueueAction(currentDatatemp);
}));
} ,
Appreciate your help
Best Answer
Hope you have figured this out by now @erikvm :-)
For other viewers, have a look at this very helpful page:
https://rajvakati.com/2018/02/18/usage-of-lightningdatatable/
Also, the fetchData function, which is missing from the 'Documentation' tab, is shown on the 'Example' tab:
lightning:datatable documentation