olivier olivier - 3 months ago 95
TypeScript Question

searchbar with filter and from JSON data with ionic 2

I'm very new to typescript and ionic 2 and I'm trying to filter trough a json response with ionic 2 search bar.

This is my code:

import {Component} from '@angular/core';
import {NavController} from 'ionic-angular';
import {Http} from '@angular/http';
import 'rxjs/add/operator/map';



@Component({
templateUrl: 'build/pages/home/home.html'
})
export class HomePage {

posts: any;
private searchQuery: string = '';
private items: string[];
constructor(private http: Http) {

this.initializeItems();

this.http.get('https://domain.co/open.jsonp').map(res => res.json()).subscribe(data => {
this.posts = data;
console.log(this.posts);

});

}

initializeItems() {
this.items = this.posts;
}

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.items = this.items.filter((item) => {
return (item.toLowerCase().indexOf(val.toLowerCase()) > -1);
})
}
}

}


And the Markup:

<ion-header>
<ion-searchbar (ionInput)="getItems($event)" [debounce]="500" placeholder="Suchen..."></ion-searchbar>
</ion-header>

<ion-content>
<ion-list>
<ion-item *ngFor="let post of posts">
<h1>{{post.storeName}}</h1>
</ion-item>
</ion-list>
</ion-content>


I this error when I search:


item.toLowerCase is not a function


The JSON data looks like this:

[
{
storeName: "Avec Hauptbahnhof",
addressLink: "",
phone: "0326223902",
image: "",
description: "",
link: "",
openingHours: [
"05.30 - 22:00",
"05.30 - 22:00",
"05.30 - 22:00",
"05.30 - 22:00",
"05.30 - 22:00",
"06.30 - 22:00",
"7.00 - 22.00"
]
},
{
storeName: "Manor",
addressLink: "",
phone: "0326258699",
image: "",
customer: "",
description: "",
link: "",
openingHours: [
"09.00 - 18.30",
"09.00 - 18.30",
"09.00 - 18.30",
"09.00 - 21:00",
"09.00 - 18.30",
"08.00 - 17.00",
"Geschlossen"
]
}
]

Answer

You're getting that error because each item is not a string, but an object, so instead of doing

item.toLowerCase().indexOf(val.toLowerCase()) > -1

You should do

item.storeName.toLowerCase().indexOf(val.toLowerCase()) > -1

Also please notice that in your view you're using the posts array

*ngFor="let post of posts" 

But you should use the items array instead, because that's the one that is going to be filtered

  <ion-list>
    <ion-item *ngFor="let item of items">
      <h1>{{item.storeName}}</h1>
    </ion-item>
  </ion-list>

Besides that, I'd do things a little bit different, just to make sure that the user is able to use the page only when the data is available (since you're using an http request to obtain it). In order to do so, I'd add a loading alert and would remove it as soon as the http request is done. As of Ionic2-beta.11, you could do that like this:

import { Component } from '@angular/core';
import { NavController, LoadingController } from 'ionic-angular';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';


@Component({
  templateUrl: 'build/pages/home/home.html'
})
export class HomePage {

  private posts: any; // <- I've added the private keyword 
  private searchQuery: string = '';
  private items: any; // <- items property is now of the same type as posts
  constructor(private http: Http, private loadingCtrl: LoadingController) {

    // this.initializeItems(); <- you don't need this anymore

    // Show the loading message
    let loadingPopup = this.loadingCtrl.create({
      content: 'Loading posts...'
    });

    this.http.get('https://domain.co/open.jsonp').map(res => res.json()).subscribe(data => {
        this.posts = data;
        this.initializeItems();

        // Hide the loading message
        loadingPopup.dismiss();
    });
  }

  initializeItems() {
    this.items = this.posts;
  }

  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.items = this.items.filter((item) => {
        return (item.storeName.toLowerCase().indexOf(val.toLowerCase()) > -1);
      })
    }
  }

}