1

The below lightning component renders data as parent-child fashion. When user search for a particular carrier name/provider it has to display only that carrier/provider data underneath.

enter image description here

Problem is i am not able to achieve the filter working properly. I did tried to have the below properties as Map and it didn't work either.

<aura:attribute name="InsAcceptedData" type="String[]" default=""/>
<aura:attribute name="filteredAcceptedData" type="String[]"  default=""/>

When I print "InsAccpetedData" it is coming as [Object Object] and when I do JSON.stringify it does give me the proper JSON.

var tempData = JSON.stringify(component.get(InsAcceptedData));

Here is the object structure. I should be able to search by carrier Name or provider first/last Name. And If I search by provider first/last name should return all possible carriers as one provider might be supporting more than one carrier. If I search by carrier it should return only that carrier.

enter image description here

Component

<aura:component
      implements="force:hasRecordId,flexipage:availableForRecordHome,force:hasSObjectName"
      controller="PDS_FindAcceptedInsurance"
    >
      <aura:attribute name="InsAcceptedData" type="String[]" default=""/>
      <aura:attribute name="filteredAcceptedData" type="String[]"  default=""/>
      <aura:attribute name="InsAcceptedcolumns" type="List" /> 
      <aura:handler name="init" value="{!this}" action="{!c.fetchInsAccpt}" />  
      
      <div class="slds-is-relative">  
        <lightning:layout horizontalAlign="left" >
            <lightning:layoutItem size="1" padding="around-small" flexibility="auto" class="slds-m-top_medium">
                <lightning:button onclick="{!c.handleKeyUp }"
                                  variant="brand"
                                  label="Search"
                                  iconName="utility:search"                              
                                  /> 
            </lightning:layoutItem>
        </lightning:layout>  
        <div style="height: 600px;">
          <lightning:treeGrid
          aura:id="treegrid_async"
          columns="{!v.InsAcceptedcolumns}"
          data="{! v.InsAcceptedData }"
          keyField="carrierName"       
          hideCheckboxColumn = "true"      
          />
        </div>
      </div>
    </aura:component>

.js

handleKeyUp: function (component, event, helper) {
    var searchFilter = component.find("SearchBox").get("v.value");    
    if (searchFilter) {  
     helper.searchDataHelper(component, event);
    }
  }

Helperclass

searchDataHelper: function (component, event) {
    var currdata = component.get("v.filteredAcceptedData");
    var alldata = component.get("v.InsAcceptedData");
    var searchFilter = component.find("SearchBox").get("v.value").toLowerCase();    
        
    var searchRes =  alldata.filter(
        (value) =>
          !searchFilter ||
          value.fName.indexOf(searchFilter) >
            -1 ||
            value.lName.indexOf(searchFilter) >
            -1 ||
            value.carrierName.indexOf(searchFilter) > -1
      );
    
    component.set("v.filteredAcceptedData", searchRes);
    console.log('searchRes==>'+searchRes); 

    
    if (filtereddata == "") {
      // set unfiltered data to data in the table.
      component.set("v.filteredAcceptedData", currdata);
      var toastReference = $A.get("e.force:showToast");
      toastReference.setParams({
        type: "warning",
        title: "No Data",
        message: "No records found for your search criteria",
        mode: "dismissible"
      });
      toastReference.fire();
    }
  }

Based on @Casper Harmer recommendation here is the working code

searchDataHelper: function (component, event) {
var currdata = component.get("v.filteredAcceptedData");
var alldata = component.get("v.InsAcceptedData");
var searchFilter = component.find("SearchBox").get("v.value");    
var tempArray = [];
var i;
let filtered = [];
alldata.forEach(value=>{
  if (value.carrierName.includes(searchFilter.toLowerCase()) || value.carrierName.includes(searchFilter.toUpperCase())){
    filtered.push(value);   
    return;    
  }
  //if carriername matches, push whole object
  else{        
    //if some of the children match, build a new child array and push
    let newchildren = [];
    value._children.forEach((child)=>{           
      if ((child.fName.includes(searchFilter.toLowerCase()) || child.fName.includes(searchFilter.toUpperCase())) 
            || (child.lName.includes(searchFilter.toLowerCase()) || child.lName.includes(searchFilter.toUpperCase()))){
        newchildren.push(child);        
      }
    });
    if (newchildren.length){
      filtered.push({"carrierName":value.carrierName,"_children":newchildren});
    }
  }
  
});
component.set("v.filteredAcceptedData", filtered);

1 Answer 1

2

You have not actually assigned the treegrid to show the filtered data.

A good idea is to ALWAYS show the filtered data, and initially just make it the same as the full data set ( InsAcceptedData )

So, link the treegrid:

<lightning:treeGrid
      data="{!v.filteredAcceptedData}" 
      .... etc
/>

In an init function, set the filtered to the full (just to start with). Actually, you have one: fetchInsAccpt - just add to the end of that.

component.set("v.filteredAcceptedData", component.get("v.InsAcceptedData"));

Your final issue is that you are trying to filter a multi level object as though it was only single level.

Your structure:

[{"carrierName":"Health R Us",
  "_children": [
    {"fname":"sandy","lname":"jones",.....},
    {"fname":"sue",  "lname":"smith",.....}
  ]
 }
] 

To filter this, it's hard to use a filter function, because you need to both filter parent names and filter child names. I think you'll need a forEach here:

let filtered = [];
alldata.forEach(value=>{
  //if carriername matches, push whole object
  if (value.carrierName.indexOf(searchFilter) > -1){
    filtered.push(result);
    return;
  }
  else {
    //if some of the children match, build a new child array and push
    let newchildren = [];
    value._children.forEach((child)=>{
      if (child.fname.indexOf(searchFilter) || child.lname.indexOf(searchFilter)){
        newchildren.push(child);
      }
    });
    if (newchildren.length){
      filtered.push({"carrierName":value.carrierName,"_children":newchildren});
    }
  }
});
6
  • Thanks for taking time to answer. Problem is when filter code executed it throws an error "Cannot read properties of undefined (reading 'indexOf')" and when I try print the "filteredAcceptedData" it is returning json object.
    – user28452
    Nov 29, 2022 at 14:48
  • Thanks for the response. I just updated the question.
    – user28452
    Nov 29, 2022 at 18:50
  • Thank you @Caspar Harmer. For some reasons it is still complaining about the object. Getting error as "Cannot read properties of undefined (reading 'indexOf') "
    – user28452
    Nov 29, 2022 at 21:25
  • at this point you are going to have to debug to see why that particular object property is not there. Nov 29, 2022 at 21:36
  • Thanks for your time. It worked using value.carrierName === searchFilter.toUpperCase()
    – user28452
    Nov 29, 2022 at 22:32

You must log in to answer this question.

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