1

I am trying to build Alphabet base filter in LWC Datatable. I want to filter opportunity name based on the Alphabet pressed by the user i.e if letter 'A' is pressed then I should see only those opportunities where opportunity name starts with letter 'A' .This is where i am not able to find a solution how to filter the datatable based on the action of the user , I want to do this filter in js file as I already have the data which needs to be filtered. if somebody has implemented the same kind of functionality and can share the knowledge that will be helpful.

JS code snippet

handleLetterFilter(event){
    this.allProducts = [...this.products];
    let letter = event.target.text;
    console.log('This is the letter ',letter);
    if(letter != 'ALL'){

    } else {
        console.log('This is the length',this.allProducts.length);
    }
}

HTML code Snippet

 <ul class="slds-list_horizontal slds-has-block-links_space">
    <li><a onclick={handleLetterFilter}>A</a></li>
    <li><a>B</a></li>
    <li><a>C</a></li>
    <li><a>D</a></li>
    <li><a>E</a></li>
    <li><a>F</a></li>
    <li><a>G</a></li>
    <li><a>H</a></li>
    <li><a>I</a></li>
    <li><a>J</a></li>
    <li><a>K</a></li>
    <li><a>L</a></li>
    <li><a>M</a></li>
    <li><a>N</a></li>
    <li><a>O</a></li>
    <li><a>P</a></li>
    <li><a>Q</a></li>
    <li><a>R</a></li>
    <li><a>S</a></li>
    <li><a>T</a></li>
    <li><a>U</a></li>
    <li><a>V</a></li>
    <li><a>W</a></li>
    <li><a>X</a></li>
    <li><a>Z</a></li>
    <li><a onclick={handleLetterFilter}>ALL</a></li>
  </ul>
4
  • What specific problem you are facing, can you add the code here? Commented May 29, 2020 at 14:26
  • There is a section of the lightning-datatable documentation about filters that will be helpful (under Creating Header Actions).
    – nbrown
    Commented May 29, 2020 at 14:31
  • @nbrown i checked but there is no clear answer Commented May 29, 2020 at 14:34
  • 1
    Please read How to Ask and then edit your post to contain a specific, detailed question with the relevant code.
    – David Reed
    Commented May 29, 2020 at 14:42

3 Answers 3

3

You need a separate variable to show the filtered results. I wrote a complete example in this playground.


<template>
    <lightning-card title="Filters">
        <div class="slds-align_absolute-center">
    <template for:each={alphabet} for:item="letter">
        &nbsp;<a onclick={handleFilterChange} key={letter} data-filter={letter}>
            {letter}
        </a>
        &nbsp;|
    </template>
    <a onclick={handleFilterChange} data-filter="">
        ALL
    </a>
        </div>
    <lightning-datatable 
        columns={columns}
        data={currentPage}
        key-field="index">
    </lightning-datatable>
    <div class="slds-align_absolute-center">
    <lightning-button-group>
    <lightning-button label="First" onclick={firstPage}>
    </lightning-button>
    <lightning-button label="Previous" onclick={previousPage}>
    </lightning-button>
    <div class="slds-m-horizontal_medium slds-align_absolute-center">
    {pageNumber} of {maxPageNumber}
    </div>
    <lightning-button label="Next" onclick={nextPage}>
    </lightning-button>
    <lightning-button label="Last" onclick={lastPage}>
    </lightning-button>
    </lightning-button-group>
    </div>
    </lightning-card>
</template>

import { LightningElement } from "lwc";

const NAMES = [
  "Noah", ...
   // Top 2k baby names of 2016 //
];

export default class App extends LightningElement {
  filteredResults = [];
  currentLetter;
  pageNumber = 1;
  pageSize = 10;
  columns = [
      { fieldName: 'name', label: 'Name', type: 'text' }
  ];
  alphabet;
  connectedCallback() {
      this.alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
      this.handleFilterChange();
  }
  nextPage() {
    this.pageNumber = Math.min(
      this.pageNumber + 1,
      this.maxPageNumber
    );
  }
  previousPage() {
    this.pageNumber = Math.max(1, this.pageNumber - 1);
  }
  firstPage() {
    this.pageNumber = 1;
  }
  lastPage() {
    this.pageNumber = this.maxPageNumber;
  }
  get maxPageNumber() {
    return Math.floor(
      (this.filteredResults.length + (this.pageSize - 1)) / this.pageSize
    );
  }
  get currentPage() {
    return this.filteredResults.slice(
      (this.pageNumber - 1) * this.pageSize,
      this.pageNumber * this.pageSize
    ).map((name,index)=>({ key: index, name }));
  }
  handleFilterChange(event) {
    if(event) {
        this.currentLetter = event.target.dataset.filter;
    }
    if (this.currentLetter) {
      this.filteredResults = NAMES.filter((name) =>
        name.startsWith(this.currentLetter)
      );
    } else {
      this.filteredResults = [...NAMES];
    }
    this.filteredResults.sort((a,b)=>a<b?-1:1);
    this.pageNumber = 1;
  }
}
1
  • thanks a lot i will try to implement the same Commented May 29, 2020 at 20:52
1

First, I want to dissect this statement:

I already have the data which needs to be filtered

Salesforce typically places limits on how much data you can query for and store. You either don't have all the data, or are very likely to reach limits related issues and slow performance. You should never query for the full data set all at once.

Next to the answer to your question.

The way I would approach this is to create a set of methods that can easily build a query dynamically. Then, to filter all you would do is add your letter to a like clause at the end of the query: WHERE Name LIKE \'' + filterLetter '%\'';

This is an approach I used a while back in visualforce components. Disclaimer: If I had the time I would love to rewrite this and possibly provide an LWC version. It does not follow best practices but it will illistrate the point.

This example does take advantage of the standard set controller. It will only query for the first "page" of records. When you click to the next page you will have to query for more records. There's a few ways to achieve this either manually or taking advantage of the custom set controller and storing necessary information about the set controller's state in a json object on the JS side to pass back to the controller in each call.

1
  • Thanks for your input yes i am filtering the data from apex Commented May 29, 2020 at 20:56
1

As @gNerb said to avoid performance issues, your data should not exceed a certain limit.

You can see the example below on this Playground

   <lightning-input type="search" label="Search" onchange={handleSearchPhone}>
    </lightning-input>
    <lightning-datatable data={phones} columns={columns} key-field="id">
    </lightning-datatable>
export default class App extends LightningElement {
    _phones = [

        { id: '1', name: 'Nokia Lumia' },
        { id: '2', name: 'Samsung Galaxy Note' },
        { id: '3', name: 'Iphone 25' },
        { id: '4', name: 'Nokia 3310' },
        { id: '5', name: 'Samsung Galaxy S50' },
     ];
    phones = [];
    columns = [
        { label: 'Available phones', fieldName: 'name' }
    ];
    connectedCallback() {
        this.phones = [...this._phones];
    }
    handleSearchPhone(event) {
        const inputValue = event.target.value[0];
        console.log('inputValue', inputValue);

        const regex = new RegExp(`^${inputValue}`, 'i');     
        this.phones = this._phones.filter(row => regex.test(row.name));

        if (!event.target.value) {
            this.phones = [...this._phones];
        }
    }
}

1
  • thanks i will try the above approach Commented May 29, 2020 at 20:53

You must log in to answer this question.

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