LWC Recipe: Searchable Product Table with Table-Only Loading
In this quick LWC recipe, you’ll learn how to build a responsive searchable product datatable using a scoped loading spinner that appears only inside the table — keeping the rest of the UI, like the search input, smooth and uninterrupted.
No full-page reloads. No input flicker. Just clean UX.
📦 What You Need
- Apex Class (
ProductService) to fetch product data - LWC Component with a search input, spinner, and datatable
🔧 Apex: ProductService.cls
public with sharing class ProductService {
@AuraEnabled(cacheable=true)
public static List<PricebookEntry> getProducts(String searchTerm) {
return [
SELECT Id, UnitPrice, Product2.Name
FROM PricebookEntry
WHERE Product2.Name LIKE :('%' + searchTerm + '%')
AND IsActive = TRUE
LIMIT 50
];
}
}
🧩 Component HTML: productTable.html
<template>
<lightning-card title="Product List">
<lightning-input
type="search"
label="Search"
value={searchTerm}
onchange={handleSearch}>
</lightning-input>
<template if:true={isTableLoading}>
<div class="slds-m-vertical_medium slds-align_absolute-center">
<lightning-spinner alternative-text="Loading..." size="small"></lightning-spinner>
</div>
</template>
<lightning-datatable
key-field="Id"
data={filteredProducts}
columns={columns}>
</lightning-datatable>
</lightning-card>
</template>
🧠 Component JS: productTable.js
import { LightningElement, track } from 'lwc';
import getProducts from '@salesforce/apex/ProductService.getProducts';
export default class ProductTable extends LightningElement {
@track products = [];
@track searchTerm = '';
@track isTableLoading = false;
debounceTimer;
columns = [
{ label: 'Name', fieldName: 'ProductName' },
{ label: 'Price', fieldName: 'UnitPrice', type: 'currency' }
];
connectedCallback() {
this.loadInitialProducts();
}
loadInitialProducts() {
this.isTableLoading = true;
getProducts({ searchTerm: '' })
.then(result => {
this.products = result.map(entry => ({
Id: entry.Id,
ProductName: entry.Product2.Name,
UnitPrice: entry.UnitPrice
}));
})
.finally(() => {
this.isTableLoading = false;
});
}
handleSearch(event) {
this.searchTerm = event.target.value;
clearTimeout(this.debounceTimer);
this.debounceTimer = setTimeout(() => {
this.fetchFilteredProducts();
}, 400);
}
fetchFilteredProducts() {
this.isTableLoading = true;
getProducts({ searchTerm: this.searchTerm })
.then(result => {
this.products = result.map(entry => ({
Id: entry.Id,
ProductName: entry.Product2.Name,
UnitPrice: entry.UnitPrice
}));
})
.finally(() => {
this.isTableLoading = false;
});
}
get filteredProducts() {
return this.products;
}
}
✅ Result
- Typing in the search input shows a small spinner inside the table
- The input stays focused — no full UI reload
- Performance is smoother and users stay happy
That’s it — a clean and elegant solution for live filtering a datatable in LWC without disrupting the entire component.
📁 View the Full Working Project on GitHub
You can browse or clone the complete working example on GitHub:
👉 https://github.com/sivanirina/lwc_table_reload_demo
Happy coding! 🚀
Comments
Post a Comment