0

I am trying to implement a pipe which filters a nested array. The following is my code and I have tried the solutions given on Stack Overflow but didn't succeed.

HTML Template:

<div>
  <div class="card-header" *ngFor="let acc of abb | search: searchTerm; let i = index">
    {{acc.gname}}
    <ng-container *ngFor="let ret of acc.desc; let j = index">
      <div class="card-body">
        {{ret.id}} - {{ret.ename}}
      </div>
    </ng-container>        
  </div>
</div>

Component Code:

this.abb = [
  {gname:'gname3', desc:[{id:123, ename:'Australia'}, {id:456, ename:'Austria'}], gid:7777},
  {gname:'gname1', desc:[{id:899, ename:'France'}], gid:8876},
  {gname:'gname2', desc:[{id:676, ename:'Germany'}], gid:0993}
];

SearchPipe:

export class SearchPipe implements PipeTransform {
  transform(value: any[], searchName: string, key = 'gname'): any[] {
    const products: any = [];
    value.forEach(product => {
      const matches = product[key].filter(({ name }) => name === searchName);
      if (matches.length) {
        products.push({ ...product, [key]: matches });
      }
    })
      
    return products;
  }
}

I am also getting an error in the line const matches = product[key].filter(({ name }) => name === searchName) which says Binding element 'name' implicitly has an 'any' type.ts(7031).

I want to filter gname and ename when the user types in the searchbox. Other filter implementations give me only gname but not ename. Any quick solution would be very appreciated.

SparkFountain
  • 2,110
  • 15
  • 35

1 Answers1

0

Context
It seems like you need a recursive object search, because the ename properties are on a different level than the gname properties. However, you should specify a few things first:

  1. What structure do the array objects have? Are ename and gname always at the same object level or can their occurrence vary?
  2. What exactly should the SearchPipe return? The whole object in which the search property occurs, or only the nested object at the object level where the search is successful?
  3. Should the properties you are searching also match any criteria? Or is it enough to simply have the property existing in the object, regardless of its value?

Solution Approch
Considering your component code, if you would like to

  • retrieve all top level objects
  • which contain at least one of the properties gname or ename
  • where gname occurs on top level
  • and where ename occurs nested in a desc array

Then the following pipe would be a solution approach.

transform(array: any[], searchName: string, key: string = 'gname'): any[] {
  const products: any = [];
  array.forEach((product: any) => {
    const match = product.hasOwnProperty('gname') || product.desc?.filter((el: any) => el.hasOwnProperty('ename')).length > 0;
    if (match) {
      products.push(product);
    }
  });
      
  return products;
}

If you need a more general approach (searching on different levels), please have a look for recursive object iteration. A good starting point might be this article.

TypeScript Error Explanation
The error message you receive in your SearchPipe implementation comes from TypeScript. Whenever you use Destructuring Assignments you have to provide the data types of all object properties you declare. In your case, the statement should become:

const matches = product[key].filter(({ name: string }) => name === searchName);

More information about TypeScript's type declaration rules (and how to suppress warnings) can be found in this StackOverflow article: Binding element 'index' implicitly has an 'any' type.

SparkFountain
  • 2,110
  • 15
  • 35
  • Hi @SparkFountain, yes structure of objects remain the same this.abb = [ {gname:'gname3', desc:[{id:123, ename:'Australia'}, {id:456, ename:'Austria'}], gid:7777}, {gname:'gname1', desc:[{id:899, ename:'France'}], gid:8876}, {gname:'gname2', desc:[{id:676, ename:'Germany'}], gid:0993}]; how ever number of objects inside desc might vary.If user searches for for gname or ename then only that particular result with matching text should be returned.Yes I think recursive search is needed.And I tried the filter implementation provided by you it didnt work any other soultion will be helpful – Vinodh Ganesh Feb 16 '23 at 16:40