Reputation: 246
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
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
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