Joe
Joe

Reputation: 246

ionic searchbar filter is not a function

I am developing an ionic app. I want show the list of countries in search bar when using keyword. I am fetching the data from api. It is working for

[
  'Amsterdam',
  'Berlin',
  'Bueno Aires',
  'Madrid',
  'Paris'
];

But itis not working for the json array.

[{
    "name": "Afghanistan",
    "topLevelDomain": [".af"],
    "languages": ["ps", "uz", "tk"],
    "translations": {
        "de": "Afghanistan",
        "es": "Afganistán",
        "fr": "Afghanistan",
        "ja": "アフガニスタン",
        "it": "Afghanistan"
    },
    "relevance": "0"
}, {
    "name": "Åland Islands",
    "topLevelDomain": [".ax"],
    "languages": ["sv"],
    "translations": {
        "de": "Åland",
        "es": "Alandia",
        "fr": "Åland",
        "ja": "オーランド諸島",
        "it": "Isole Aland"
    },
    "relevance": "0"
}]  

The error is showing as

TypeError:_this.items.filter is not a function

Below shown as the code.

export class ModalPage{
    resp;
    items: array<any>;
    showList;

    constructor(public navCtrl: NavController, public rest: RestProvider) {

    }

    ionViewDidLoad() {
        console.log('ionViewDidLoad ModalPage');
    }

    getItems(ev: any){
         let val = ev.target.value;
         /**   call api ***/

            this.rest.selectCountryFn(val)
                .then(data => {
                this.items = data;
                this.items = JSON.stringify(data);
                console.log("json :"+this.items);   //json is shown as correct

                if (val && val.trim() != '') {

                    // Filter the items
                    this.items = this.items.filter((item) => {
                    return (item.toLowerCase().indexOf(val.toLowerCase()) > -1);
                });


            } else {

                    // hide the results when the query is empty
                    this.showList = false;
                }

            });

            /*** api call end  ****/
        }
}

html code

<ion-searchbar (ionInput)="getItems($event)"></ion-searchbar>
   <ion-list *ngIf="showList">
    <ion-item *ngFor="let item of items" (click)="select(item.name)">
      {{ item.name }}
    </ion-item>
</ion-list>

Please help me. I have tried different methods. But i didn't get the result..

Upvotes: 0

Views: 1001

Answers (2)

Joe
Joe

Reputation: 246

I got the answer. I convert the json data to array. I used items: any; for declaration. And i used

const usersJson: any[] = Array.of(this.items);

for converting json to array. For adding the list after filter. I used

this.items = <any[]>JSON.parse(this.items);

And the final code is,

export class ModalPage{
    resp;
    items: any;
    showList;

    constructor(public navCtrl: NavController, public rest: RestProvider) {

    }

    ionViewDidLoad() {
        console.log('ionViewDidLoad ModalPage');
    }

    getItems(ev: any){
         let val = ev.target.value;
         /**   call api ***/

            this.rest.selectCountryFn(val)
                .then(data => {
                this.items = data;

                const usersJson: any[] = Array.of(this.items);



                if (val && val.trim() != '') {

                    // Filter the items
                    this.items = usersJson.filter((item) => {
                    return (item.toLowerCase().indexOf(val.toLowerCase()) > -1);
                });

                this.items = <any[]>JSON.parse(this.items);

                this.showList = true;


            } else {

                    // hide the results when the query is empty
                    this.showList = false;
                }

            });

            /*** api call end  ****/
        }
}

Upvotes: 0

Alexander Staroselsky
Alexander Staroselsky

Reputation: 38757

The issue should be with the following line specifically:

this.items = JSON.stringify(data);

Once this is executed, this.items is no longer a valid JavaScript array that would have Array.prototype.filter method available, as it becomes a String with JSON.stringify(). You wouldn't need to do JSON.stringify() at this moment anyway, you can always JSON.stringify() the entire data after filtering before sending to your API.

getItems(ev: any) {
  let val = ev.target.value;
  /**   call api ***/

  this.rest.selectCountryFn(val)
    .then(data => {
      this.items = data;
      console.log("json :"+this.items);   //json is shown as correct

      if (val && val.trim() != '') {
        // Filter the items
        this.items = this.items.filter((item) => {
          return JSON.stringify(item).toLowerCase().indexOf(val.toLowerCase()) > -1;
        });
      } else {
        // hide the results when the query is empty
        this.showList = false;
      }
    });
    /*** api call end  ****/
}

With that being removed, you will need to update your filter() statement to do something like stringifying each item to use with indexOf() or targeting specific object properties for comparison:

this.items = this.items.filter((item) => {
  return JSON.stringify(d).toLowerCase().indexOf(val.toLowerCase()) > -1;
});

The last thing is your definition of class property items: array<any>; is incorrect. It would need to be items: any[]; or items: Array<any>; with a capital "A". That being said, I'd recommend to always try to provide a default value, in this case an empty array items: any[] = [];, but even better would be creating an interface/class to represent your data structure:

export interface Country {
  name: string;
  topLevelDomain: string[];
  languages: string[];
  translations: { [key: string]: string };
  relevance: string;
}

items: Country[] = [];

I made an Ionic StackBlitz to show this functionality in action at a basic level.

Below is the basic JavaScript of this functionality:

const data = [{
  "name": "Afghanistan",
  "topLevelDomain": [".af"],
  "languages": ["ps", "uz", "tk"],
  "translations": {
    "de": "Afghanistan",
    "es": "Afganistán",
    "fr": "Afghanistan",
    "ja": "アフガニスタン",
    "it": "Afghanistan"
  },
  "relevance": "0"
}, {
  "name": "Åland Islands",
  "topLevelDomain": [".ax"],
  "languages": ["sv"],
  "translations": {
    "de": "Åland",
    "es": "Alandia",
    "fr": "Åland",
    "ja": "オーランド諸島",
    "it": "Isole Aland"
  },
  "relevance": "0"
}];

const val = 'AF';

const items = data.filter(d => {
  return JSON.stringify(d).toLowerCase().indexOf(val.toLowerCase()) > -1;
});

console.log(items);

Hopefully that helps!

Upvotes: 2

Related Questions