• About
  • Contact me!

Salesforce Everywhere

~ Blog on Salesforce Dev and admin stuff

Salesforce Everywhere

Tag Archives: Lightning Data Table

Lightning component to filter Products and display results in lightning data table

13 Monday Apr 2020

Posted by Mani in Lightning Component

≈ 2 Comments

Tags

Lightning Component, Lightning Data Table

In this blog post, we will discuss on creating a lightning component to filter products based on Product Code and Product Name. User can type multiple codes or names separated by comma. Then, we will display the results based on the given search criteria using lightning data table.

We have accounts of type=Vendor and every product is linked to a Vendor account. We will have a Vendor picklist in the component and it gets populated with the distinct values from the Vendor Number column on the search results.

Apex Class:

public with sharing class SearchProductController {
 
 @AuraEnabled public List<String> result{get;set;}
 @AuraEnabled public List < Product2 > returnList{get;set;}
    
 @AuraEnabled
 public static SearchProductController fetchProductbyName(String searchKeyWord) {
     
     SearchProductController obj = new SearchProductController();
     String searchKey;
     Set < String > returnSetVIds = new Set < String > ();
     List < String > returnListVIds = new List < String > ();
     try
     {
     if(searchKeyWord.contains(','))
     {
         List<String> searchKeyCode = searchKeyWord.split(',') ;
         obj.returnList = [select Name,ProductCode,Voltumcon1__Vendor_Name__c, Voltumcon1__Vendor_Number__c 
                          from Product2
                          where Name in: searchKeyCode AND IsActive=TRUE LIMIT 500
                           ];
     }
     else
     {
     
     searchKey = searchKeyWord + '%';
     obj.returnList  = [select Name,ProductCode,Voltumcon1__Vendor_Name__c,Voltumcon1__Vendor_Number__c from Product2
                                   where Name LIKE: searchKey AND IsActive=TRUE LIMIT 500];
      }
 for (Product2 prd: obj.returnList) {
   //obj.returnList.add(prd);
   returnListVIds.add(prd.Voltumcon1__Vendor_Number__c);
  }
  system.debug(returnListVIds);
  returnSetVIds.addAll(returnListVIds);
  system.debug(returnSetVIds);
  obj.result = new List<String>();
  obj.result.addAll(returnSetVIds); 
  return obj;
  }
     catch (Exception e) {
        // "Convert" the exception into an AuraHandledException
        throw new AuraHandledException('Something went wrong: '
            + e.getMessage());    
    }
 }
   
 @AuraEnabled
 public static SearchProductController fetchProductbyCode(String searchKeyWord) {
     
     SearchProductController objCode = new SearchProductController();
     List<String> searchKeyCode;
     Set < String > returnSetVIds = new Set < String > ();
     List < String > returnListVIds = new List < String > ();
     String searchKey;
     try
     {
     if(searchKeyWord.contains(','))
     {
       searchKeyCode = searchKeyWord.split(',') ;
       objCode.returnList = [select Name,ProductCode,Voltumcon1__Vendor_Name__c,Voltumcon1__Vendor_Number__c 
                          from Product2 
                          where ProductCode in: searchKeyCode AND IsActive=TRUE LIMIT 500
                           ];  
     }
     
     else
     {
      searchKey = searchKeyWord + '%';
      objCode.returnList = [select Name,ProductCode,Voltumcon1__Vendor_Name__c,Voltumcon1__Vendor_Number__c 
                           from Product2
                           where ProductCode LIKE: searchKey AND IsActive=TRUE LIMIT 500
                           ];
     }   
     
     for (Product2 prd: objCode.returnList) {
         returnListVIds.add(prd.Voltumcon1__Vendor_Number__c);
  }
  
  returnSetVIds.addAll(returnListVIds);
   objCode.result = new List<String>();
  objCode.result.addAll(returnSetVIds); 
  return objCode;
    }
     
      catch (Exception e) {
        // "Convert" the exception into an AuraHandledException
        throw new AuraHandledException('Something went wrong: '
            + e.getMessage());    
    }
 }

}

Please note that we have created 2 lists in the above class, one to hold the search results and the other one for holding Vendor Numbers.

Lightning Component:

<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId" access="global" controller="SearchProductController" >
	
    <aura:attribute name="searchKeyword" type="String" description="search input"/>
    <aura:attribute name="TotalNumberOfRecords" type="integer" default="0" description="display Total Number of records"/>
    <aura:attribute name="selectedRowsCount" type="Integer" default="0"/>
    <aura:attribute name="mycolumns" type="List"/>
    <aura:attribute name="isLoading" type="Boolean" default="false"/>
    <aura:attribute name="objClassController" type="SearchProductController"/>
    
    <aura:handler name="init" value="{! this }" action="{! c.init }"/>
    
     <!-- SHOW LOADING SPINNER--> 
    <lightning:spinner variant="brand" size="large" aura:id="Id_spinner" class="slds-hide" />
   
        <div aria-labelledby="newSearchForm" class="slds-grid">
        <!-- BOXED AREA -->
        <fieldset class="slds-box slds-theme--default slds-container--small">
 
        <label id="newSearchForm" class="slds-text-heading--small
        slds-p-vertical--medium">
        Search Products
        </label>
        
            <form class="slds-form--stacked">
                
                <lightning:select aura:id="selectfilter" name="select1" label="Filter by" onchange="{! c.onChange }" required="true" >
				<option value="Product Code">Product Code</option>
				<option value="Product Name">Product Name</option>
			</lightning:select>
                
               <lightning:input value="{!v.searchKeyword}"
                                 required="true"
                                 placeholder="search Products.."
                                 aura:id="searchField"
                                 label="Enter Value"/>
            
    
                 <lightning:button onclick="{!c.Search}"
                                   class="slds-m-top--medium"
                                  variant="brand"
                                  label="Search"
                                  iconName="utility:search"/>
                
                <br></br>
                <div class="slds-form-element__control slds-grow" >
           		<lightning:select name="VendorId" label="Vendor Id" required="true" aura:id="VendorId"
                                  messageWhenValueMissing="Select a valid value">
               	<option value="">Select</option>
         			<aura:iteration items="{!v.objClassController.result}" var="item">
            		<option value="{!item}" text="{!item}"></option>
        			</aura:iteration>
    				</lightning:select>
            </div>
           
            </form>
            </fieldset>
    	 </div>
        
       <div class="slds-m-vertical_small">
           <aura:if isTrue="{!v.objClassController.returnList.length >0}">
           <h1 class="slds-m-vertical_small"><b>Total Rows: {! v.objClassController.returnList.length }</b></h1>
           
           <aura:set attribute="else">
               <h1 class="slds-m-vertical_small"><b>Total Rows: 0</b></h1>
           </aura:set>
           </aura:if>
               <h1 class="slds-m-vertical_small"><b>Selected Rows: {! v.selectedRowsCount }</b></h1>
           
             
    <lightning:datatable data="{! v.objClassController.returnList }"
        columns="{! v.mycolumns }"
        aura:id="avreltable"                 
        onrowselection="{!c.updateSelectedText}"
        onsort="{! c.updateColumnSorting }"                 
        keyField="Id"/>
        
    </div>
    
</aura:component>

Points to note in the above component:

a. We are using lightning:datatable to display search results. Data table is a table that displays columns of data, formatted according to type. This is one of the base component provided by the Lightning framework. Please refer this link for more details https://developer.salesforce.com/docs/component-library/bundle/lightning:datatable/example

b. We have created an attribute “objClassController” of apex class type to fetch the lists from the class to display the search results and Vendor numbers.

JS Controller:

({
   init: function (cmp, event, helper) {
        cmp.set('v.mycolumns', [
            
            { label: 'Product Name', fieldName: 'Name', sortable: true,type: 'text'},
            { label: 'Product Code', fieldName: 'ProductCode', sortable: true,type: 'text'},
            { label: 'Vendor', fieldName: 'Voltumcon1__Vendor_Name__c',sortable: true,type: 'text'},
            { label: 'Vendor Number', fieldName: 'Voltumcon1__Vendor_Number__c',sortable: true,type: 'text'}
        ]);
		
    },
    
    updateSelectedText: function (cmp, event) {
        var selectedRows = event.getParam('selectedRows');
        cmp.set('v.selectedRowsCount', selectedRows.length);
        },
    
    Search: function(component, event, helper) {
        var searchField = component.find('searchField');
        var isValueMissing = searchField.get('v.validity').valueMissing;
        // if value is missing show error message and focus on field
        if(isValueMissing) {
            searchField.showHelpMessageIfInvalid();
            
        }else{
          // else call helper function 
            helper.SearchHelper(component, event);
            
        }
    },
    
    onChange: function (cmp, evt, helper) {
    
    cmp.set('v.searchKeyword',null);
    },
    
    updateColumnSorting: function (cmp, event, helper) {
        cmp.set('v.isLoading', true);
        // We use the setTimeout method here to simulate the async
        // process of the sorting data, so that user will see the
        // spinner loading when the data is being sorted.
        setTimeout(function() {
            var fieldName = event.getParam('fieldName');
            var sortDirection = event.getParam('sortDirection');
            cmp.set("v.sortedBy", fieldName);
            cmp.set("v.sortedDirection", sortDirection);
            helper.sortData(cmp, fieldName, sortDirection);
            cmp.set('v.isLoading', false);
        }, 0);
    }
    
})

Helper function:

({
    SearchHelper: function(component, event) {
        // show spinner message
         component.find("Id_spinner").set("v.class" , 'slds-show');
        
        var filter = component.find("selectfilter").get('v.value');
        
        	if(filter == "Product Code")
            {
              var action = component.get("c.fetchProductbyCode");  
            }
         	else if(filter == "Product Name")
         	{
          	var action = component.get("c.fetchProductbyName");   
         	}
        	action.setParams({
            'searchKeyWord': component.get("v.searchKeyword")	
        });
        action.setCallback(this, function(response) {
           // hide spinner when response coming from server 
            component.find("Id_spinner").set("v.class" , 'slds-hide');
            var state = response.getState();
            if (state === "SUCCESS") {
                var storeResponse = response.getReturnValue();
                component.set('v.objClassController', storeResponse);
            
            }else if (state === "INCOMPLETE") {
                alert('Response is Incompleted');
            }else if (state === "ERROR") {
                var errors = response.getError();
                if (errors) {
                    if (errors[0] && errors[0].message) {
                        alert("Error message: " + 
                                    errors[0].message);
                    }
                } else {
                    alert("Unknown error");
                }
            }
        });
        $A.enqueueAction(action);
    },
    
    sortData: function (cmp, fieldName, sortDirection) {
        var data = cmp.get("v.objClassController.returnList");
        var reverse = sortDirection !== 'asc';

        data = Object.assign([],
            data.sort(this.sortBy(fieldName, reverse ? -1 : 1))
        );
        cmp.set("v.objClassController.returnList", data);
    },
    sortBy: function (field, reverse, primer) {
        var key = primer
            ? function(x) { return primer(x[field]) }
            : function(x) { return x[field] };

        return function (a, b) {
            var A = key(a);
            var B = key(b);
            return reverse * ((A > B) - (B > A));
        };
    }
    
       
})

Output Screenshots:

Clicking on Search button without giving any value throws error:

Search on Product codes by entering them with comma separated values. Vendor Id got auto populated with the distinct Vendor Numbers from the search results:

Component will do a wildcard search for the entered value(in this case ‘SL’):

When the rows are selected, Selected rows will show the count of selected rows:

Wildcard search for the Product Name:

Exact search for the Product Name:

Please let me know for any questions. Thanks and stay safe!!

Blog Stats

  • 111,812 hits

Archives

Recent Posts: Salesforce Everywhere

How to get field values on onLoad in lightning-record-edit-form in LWC?

Using Dynamic Actions

How to check if the logged in user is a Guest user or not in APEX class?

How to Close Quick action in LWC

Lightning component to filter Products and display results in lightning data table

Connect with me

  • View @manibalan_s’s profile on Twitter
  • LinkedIn

Developer links

  • Salesforce Developer website
  • Salesforce Success Community

Enter your email address and click on Follow us (below) to follow this blog and receive notifications of new posts by email.

Website Powered by WordPress.com.

  • Follow Following
    • Salesforce Everywhere
    • Already have a WordPress.com account? Log in now.
    • Salesforce Everywhere
    • Customize
    • Follow Following
    • Sign up
    • Log in
    • Report this content
    • View site in Reader
    • Manage subscriptions
    • Collapse this bar