I am fetching data from a JSON file that's stored locally within my project. The JSON string is an array of locations, whose structure is like so:
JSON file
{
"locations": [
{
"title": "ABC",
"latitude": -1.2596551,
"longitude": 36.7066604,
"routes":["22","23","105","115"],
"fare":[],
"matatu":[]
},
{
"title": "Adams Arcade",
"latitude": -1.3004204,
"longitude": 36.7770793,
"routes": ["2","4W","102","24","24C","111"],
"fare":[],
"matatu":[]
},
{
"title":"Aga Khan Hospital",
"latitude":-1.2620125,
"longitude":36.8186399,
"routes":["11A","11F","106","107","116"],
"fare":[],
"matatu":[]
}
]
}
Rather than filtering the data on the fly with a pipe, I have implemented a function in my provider
to handle this. Here's the code:
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
import { Geolocation } from '@ionic-native/geolocation';
@Injectable()
export class LocationProvider {
data: any;
constructor(public http: Http, public geolocation: Geolocation) {
}
load(){
if(this.data){
return Promise.resolve(this.data);
}
return new Promise(resolve => {
this.http.get('assets/data/locations.json').map(res => res.json()).subscribe(data => {
this.data = this.applyHarvesine(data.locations);
this.data.sort((locationA, locationB) => {
return locationA.distance - locationB.distance;
});
resolve(this.data);
});
});
}
filterLocations(searchTerm){
return this.data.filter((location) => {
return location.title.toLowerCase().indexOf(searchTerm.toLowerCase()) > -1;
});
}
}
The filterLocations()
function is to take in searchTerm
and returns an array containing only the elements that match the search criteria.
Here's the .ts
and .html
code for the page where it is rendered.
.ts
import { Component } from '@angular/core';
import { IonicPage, NavController } from 'ionic-angular';
import { LocationProvider } from '../../providers/location/location';
import { PlaceDetailsPage } from '../place-details/place-details';
@IonicPage()
@Component({
selector: 'page-places',
templateUrl: 'places.html',
})
export class PlacesPage {
searchTerm: string = '';
constructor(public navCtrl: NavController, public locations: LocationProvider) {
}
ionViewDidLoad() {
this.setFilteredLocations();
}
setFilteredLocations(){
return this.locations.filterLocations(this.searchTerm);
}
}
.html
<ion-content>
<ion-searchbar [(ngModel)]="searchTerm" (ionInput)="setFilteredLocations()"></ion-searchbar>
<ion-list no-lines>
<button ion-item *ngFor="let location of locations.data">
<ion-avatar item-left>
<ion-icon name="pin"></ion-icon>
</ion-avatar>
<h2>{{location.title}}</h2>
<p>{{location.distance}} km</p>
</button>
</ion-list>
</ion-content>
When the user types on the searchbar, setFilteredLocation()
is called to trigger the filtering of data. The problem is, nothing happens.
Where have I gone wrong? My hunch is that something is amiss in the setFilteredLocation()
function, but I have no clue what it is.
Is there an alternative approach to searching and filtering that doesn't involve pipes?
You are doing it wrong.
return this.data.filter(...)
. It has no effect to your
origin array (this.data
). It just return a new array and does not make change to this.data
. See the filter function doc
this.data = this.data.filter(...)
. But if you do like that, you will fall in other mistake. Your this.data
will lost some element after filter and it can not be revert when you reset the filter.So you should do like that:
In your component:
allData = []; //Store all data from provider
filterData = [];//Store filtered data
ionViewDidEnter(){
this.allData = this.locations.data;
this.filterData = this.allData;
}
setFilteredLocations(){
this.filterData = this.allData.filter((location) => {
return location.title.toLowerCase().indexOf(this.searchTerm.toLowerCase()) > -1;
});
}
And in your template use filterData in ngFor
:
<button ion-item *ngFor="let location of filterData">
Yo didn't send the $event
here. So try as shown below.
.html
<ion-searchbar [(ngModel)]="searchTerm"
(ionInput)="setFilteredLocations($event)"></ion-searchbar>
.ts
setFilteredLocations(ev: any){
let val = ev.target.value;
if (val && val.trim() !== '') {
return this.locations.filterLocations(val);
}
}
You can see the official sample code here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With