Ion-searchbar double filter

Hi,
I’m making a page that shows a list of cards.
The data structure is in the form of an array of objects (example: [{a: 1}, {b: 2}, …]). (name of objects: FirstCategory).

Since each object is a category, each object will then have children (showcases).
Showcases are also imported as an object vector.
Each showcase has a “ParentID” field which is identical to the “ID” field owned by the parent category it belongs to.

I need to be able to filter the categories array but the search must be performed in the “Name” field of the showcase object (in the showcase array).

Anyone have any idea how I can do it?

Thanks in advance.

I would suggest something like

>       let catArr = [  ];
>       const filteredCatArray = catArr.map(category => 
>         category.showcases.filter(showcase => showcase.name === 'SearchString')
>       )

this would return a array of showcase arrays and every showcase included would have the name SearchString (Case sensitive).
To improve search try using some string operations like String.includes.

Category and Showcases are two separate data structures:
CATEGORY SHOWCASES:


SHOWCASES:

How i can implement the previous question with the ion-searchbar?
In my template i have something like this (example not working)

<ion-searchbar placeholder="Inserisci testo per la ricerca" [(ngModel)]="searchTerm" animated="true"></ion-searchbar>

  <ion-grid class="grid">
    <ion-row *ngIf="(showcases | filter:searchTerm)">
      <ion-col size="6" *ngFor="let item of category">

I mean, i can use an “onChange($event)” function and execute some code similar to your suggested code?
Or i can/need to do something else?

Ahh ok so the showcases are not directly in your category Object.

First of all you should display the filtered Array and not just *ngIf all data. We mostly use the IonChange event with a trigger delay of 300ms. I would recommend as well to map the showcases of a category directly in the category object like

Model

public class Category {
      // some other properties
     showcases: Showcase[];
}

public class Showcase {
   // all the props
   name: string;
}

.HTML

<ion-searchbar debounce="300" (ionChange)="searchArea($event.detail.value)"></ion-searchbar>
<ion-grid class="grid">
    <ion-row >
      <ion-col size="6" *ngFor="let cat of filteredCategory">
        <div *ngFor="let showcase of cat.showcases"></div>
          {{cat.name}}{{showcase.name}}
     </ion-col>
 </ion-row>
</ion-grid>

.component.ts

public searchArea(text: string) {
    this.searchValue = text;
    if (this.searchValue === '') {
      this.filteredCategories = this.selectedCategories;
      return;
    }

    this.setFilteredList();

    if (this.filteredCategories.length === 0) {
      this.searchNotMatched = true;
      return;
    }
    this.searchNotMatched = false;

  }

private setFilteredList(): void {
    this.filteredCategories = this.selectedCategories.map(category => {
      return category.showcases.filter(showcase => showcase.name === this.searchValue)
    });
  }

since the showcase depends on (or is part of the) category you have two arrays. The filteredCategory Array which is for example selected Categories and filtererdShowcases which contains all showcases with name equals the searchTerm.

I understand what you want to do, but I cannot create the Category and Showcases classes because I get data in json format from API.
Do you recommend to append an array of showcases to the category object or to use the filter in another way?

Appending the Showcase array to a category would simplify in many ways. If you want to use the current Datastructure you would have to generate a filtered showcase array for every category you want to show :confused:

I don’t know how you request your data but with rxjs you can easily create a data structure that you would prefer without changing API interface

I can provide a little snippet of combining two api requests to a single Datastructure if you want :slight_smile:

I get my data with this script:

/*get function on load-data.service*/
loadFirstCategoryShowcases() {
    return new Promise<any>((resolve) => {
      this.http.get(URL_GRAPH.FIRSTCATEGORYSHOWCASES).subscribe(async (data: any) => {
        this.first_category_showcases = await JSON.parse(JSON.stringify(data)).data.readFirstCategoryShowcases;
        resolve(this.first_category_showcases);

      })

    });
  }

/*call load data in function on page.ts */
getFirstCategoryShowcases() {
    this.load.loadFirstCategoryShowcases().then((data) => {
      console.log(data);
      this.first_category = data;
      this.storage.setItem('firstcategoryMusile', this.first_category);
    })
  }

I have never used rxjs before.
I don’t even know what it is honestly :sweat_smile:

If it can be of great help to me in case an example of how to use it / how it works would be appreciated

Ok hehe, so then I would recommend that you take a look at it because it simplifies everything :slight_smile:
In the first step you should focus on how Observables and rxjs pipes work this will help you a lot.

I show you a simple example of mapping.

    public assembleSomeData(): Observable<MyInterface> {
    const basicData = this.httpClient.get<ApiInterface>(url);
    const advancedData = this.httpClient.get<AnotherApiInterface>(anotherUrl);
    return combineLatest( basicData, advancedData ).pipe(
      map(([basicData, advancedData]) => {
        return {
          myName: basicData.name,
          myArray: advancedData.array
        } as MyInterface
    }))
  }


class MyInterface {
  myName: string;
  myArray: string[];
}

class ApiInterface {
  name: string;
  // ...
}

class AnotherApiInterface {
  array: string[];
  // ...
}

data: MyInterface;
// USAGE
this.assembleSomeData().subscribe(myMergedData => {
 // here you can do what ever you want with the data like saving into a local variable
 this.data = myMergedData;
})

this is a example of how two http calls can be merged to a preferred type. Angular provides a async pipe as well for HTML templates to observables directly in HTML without subscribing.

<div *ngIf="data | async as myData">{{myData.name}}</div>

But first of all try to understand how Observables work

hope this helps :slight_smile: