Search code examples
jsonionic3searchbar

Ionic 3 filter nested JSON with ionic searchbar


I have a question how to use ionic searchbar to filter items in a nested JSON object. As I've tried to filter the header item it worked perfectly fine but it does not work for the name wrap inside the brands.

{
"items": [{
        "header": "A",
        "brands": [{ "name": "Apple", "id": "1" }, { "name": "Adidas", "id": "2" }]
    },
    {
        "header": "B",
        "brands": [{ "name": "Bose", "id": "3" }, { "name": "Boss", "id": "4" }, { "name": "Birkenstock", "id": "5" }]
    },
    {
        "header": "M",
        "brands": [{ "name": "McDonalds", "id": "6" }]
    }
]
}

My search.ts:

    private result: any[];
  private searchItems: any;
  constructor(
    public navCtrl: NavController,
    public navParams: NavParams,
    private http: Http
  ) {
    let localData = this.http.get('assets/search-brand.json').map(res => res.json().items);
    localData.subscribe(data => {
      this.result = data;
    });
    this.initializeItems();
  }

  initializeItems() {
    this.searchItems = this.result;
  }

  getItems(ev: any) {
    // Reset items back to all of the items
    this.initializeItems();

    // set val to the value of the searchbar
    let val = ev.target.value;

    // if the value is an empty string don't filter the items
    if (val && val.trim() != '') {
      this.searchItems = this.searchItems.filter((item) => {
        return (item.header.toLowerCase().indexOf(val.toLowerCase()) > -1);
      })
    }
  }

My code (search.html):

<ion-searchbar (ionInput)="getItems($event)"></ion-searchbar>
<p>{{test}}</p>
<ion-list *ngFor="let item of searchItems; let i = index">
    <ion-list-header>
        {{item.header}}
    </ion-list-header>
    <ion-item *ngFor="let brands of item.brands; let j = index" (click)="selectedBrand(brands.id)">{{brands.name}}</ion-item>
</ion-list>

This one is working for filtering the brands.name it said .toLowerCase() is not a function.


Solution

  • Your JSON data maybe have some element with header == null or does not have brands propertive. So to ensure the search work properly, you should handle these case by if statement. You need to rewrite filter function to get expected output.
    Try this:

    this.searchItems = this.searchItems.map((item)=>{
       if(item && item.brands && item.brands.length > 0){
         item.brands = item.brands.filter(brand=>{
          if(!brand.name) return false;
          return brand.name.toLowerCase().indexOf(val.toLowerCase()) > -1;
         });
       }    
       retrun item;   
    })