9

Is there a way to search across all rows/columns in a lightning:datatable to narrow down the list, just like jQuery DataTables? If so, how do implement that?

Can I somehow do it all on the client-side to make it super fast (some sort of DOM manipulation)

I'm having some issues with the lightning:datatable not updating. I have attached my code below, maybe you can help me spot the issue:

Markup:

<aura:component 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="Object"/>
<aura:attribute name="mycolumns" type="List"/>
<aura:attribute name="sortedBy" type="String" />
<aura:attribute name="sortedDirection" type="Boolean" default="true" />

<aura:registerEvent name="AccountFilterChange" type="c:AccountFilterChange" />

<aura:attribute name="backingdata" type="List" />
<aura:attribute name="filter" type="String" />
<lightning:input type="text" onchange="{!c.filter}" value="{!v.filter}" label="Filter" />

<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}"
                     hideCheckboxColumn="true"
/>

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);
        console.log(component.get("v.backingdata") + " /// BACKING DATA INSIDE ")
        console.log(component.get("v.accounts") + " // ACCOUTN DATA INSIDE")

        component.set('v.mycolumns', [{
                type: "button",
                typeAttributes: {
                    label: '',
                    iconName: 'utility:add',
                    name: 'selectRecord',
                    title: 'selectRecord',
                    disabled: false,
                    value: 'edit',
                    variant: {
                        fieldName: 'variantValue'
                    },
                }
            },
            {label: 'Name', fieldName: 'Name', type: 'text', sortable: true},
            {label: 'Street', fieldName: 'BillingStreet', type: 'text', sortable: true},
            {label: 'Postal Code', fieldName: 'BillingPostalCode', type: 'text', sortable: true},
            {label: 'City', fieldName: 'BillingCity', type: 'text', sortable: true},
            {label: 'Country', fieldName: 'BillingCountry', type: 'text', sortable: true},
        ]);

        console.log(component.get("v.backingdata") + " *** BACKING DATA OUTSIDE *** ")
        console.log(component.get("v.accounts") + " *** ACCOUNT DATA OUTSIDE *** ")
    }))
},

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.age.toString()));
    } catch (e) {
        // invalid regex, use full list
    }
    component.set("v.accounts", results);
},

For some reason the filter function is completely unresponsive. Also, does it matter that I'm populating the component with a response from a callback function. @sfdcfox, I noticed in your example that you simple created an array with dummy data. My "myaccounts" attribute is of type object

2
  • Yes, you can do that iterate over the rows and check for the desired columns values to match and reduce the rows with the filtered rows. Commented May 28, 2018 at 9:48
  • Can you point me in the right direction? I have tried finding some examples but all of them seem to be using regular tables / aura iterations - not really sure how that will work with the lightning:datatable component
    – erikvm
    Commented May 28, 2018 at 10:56

1 Answer 1

10

Searching with a data table is the same as search with an aura:iteration. You still need to have a backing attribute to store the extra data, etc. Here's an example of what that looks like in action.


<aura:application extends="force:slds">
    <!-- backing data -->
    <aura:attribute name="data" type="List" />

    <!-- data table attributes -->
    <aura:attribute name="columns" type="List" />
    <aura:attribute name="filteredData" type="List" />

    <!-- filter input -->
    <aura:attribute name="filter" type="String" />

    <aura:handler name="init" value="{!this}" action="{!c.init}" />

    <lightning:input type="text" onchange="{!c.filter}" value="{!v.filter}" label="Filter" />
    <lightning:datatable keyField="name" columns="{!v.columns}" data="{!v.filteredData}" />
</aura:application>

({
    init: function(component, event, helper) {
        var sample = [];
        // Create 10 random people
        [...Array(10).keys()].forEach(v=>sample.push({name:"Person "+(v+1), age: Math.floor(Math.random()*80)}));
        // initialize data
        component.set("v.columns", [{type:"text",label:"Name",fieldName:"name"},{type:"number",label:"Age",fieldName:"age"}]);
        component.set("v.data", sample);
        component.set("v.filteredData", sample);
    },
    filter: function(component, event, helper) {
        var data = component.get("v.data"),
            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.age.toString()));
        } catch(e) {
            // invalid regex, use full list
        }
        component.set("v.filteredData", results);
    }
})

Hopefully, as you can see, it's mostly a matter of of simply changing the bits using aura:iteration to use lightning:datatable instead, as most of the rest of the logic is nearly identical, such as this example (my own Gist).

2
  • @erikvm Sorry, just looked at your code, you've tried to store the response, but you should have gotten the return value instead: component.set("v.backingdata", response.getReturnValue()); It's a common mistake. Also, your last few lines about "being outside" are not really outside the initial handler. In this case, the filtering would have been fine, but your problem was how you set the attribute.
    – sfdcfox
    Commented May 30, 2018 at 14:14
  • Hey, I should've been clearer, but helper.callServer actually has a variable called response that is set to response.getReturnValue. I did solve it however, by wrapping everything inside a $A.getCallback function. However, the biggest issue with the table not updating was that I had rows specified to lowercase when it should've been uppercase in the filter function (Name instead of name, BillingCity instead of billingcity etc)
    – erikvm
    Commented May 31, 2018 at 14:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .