Reputation: 436
I'm in the process of creating an app using the Ionic 2 with Angular 2 and i've hit a bit of a snag.
My app is fetching data from an API that returns a mongo object using the geonear command. This object contains a bunch of different store with info on opening hours and such:
{
"_id" : ObjectId("585723490a60e14d8a41ffd3"),
"storeID" : NumberInt(1110),
"storeName" : "Kvickly Sundby",
"chain" : "kvickly",
"phone" : NumberInt(32860111),
"openingDates" : [
{
"open" : "08.00",
"close" : "20.00",
"date" : "2016-12-13",
"_id" : ObjectId("585723490a60e14d8a41ffef")
},
{
"open" : "08.00",
"close" : "20.00",
"date" : "2016-12-14",
"_id" : ObjectId("585723490a60e14d8a41ffee")
}
],
"location" : {
"address" : "Englandsvej 28",
"city" : "København S",
"zip" : NumberInt(2300),
"coordinates" : [
12.6048,
55.65654
]
},
"__v" : NumberInt(0)
}
The data is passed on to my template, looped through and displayed on cards with an accordion function as well as a pagination function.
Fetching form the API
getStores(lat, lng) {
this.fetchUrl = this.envVar.getEnvUrl() + '?lat=' + lat + '&lng=' + lng;
console.log(this.fetchUrl);
this.http.get(this.fetchUrl)
.map(res => res.json())
.subscribe(data => {
this.stores = data;
this.loading.dismiss();
this.curPage = 1;
});
}
Template
<accordion>
<accordion-group *ngFor="let store of stores | paginate: { itemsPerPage: 15, currentPage: p }; let first = first" [isOpened]="first">
<accordion-heading>
<ion-card class="store-card" [style.border-color]="storeColor(store.obj.chain)">
<ion-row>
<ion-col width-67>
<ion-col>
<h2 class="store-name">{{store.obj.storeName}}</h2>
<p class="store-location">{{store.obj.location.address}} <br> {{store.obj.location.city}}, {{store.obj.location.zip}}</p>
<ion-icon ios="ios-arrow-down" md="ios-arrow-down"></ion-icon>
</ion-col>
</ion-col>
<ion-col width-33>
<ion-col width-100 *ngFor="let date of store.obj.openingDates | where : {date : today}" class="opening-hours"><p>{{date.open}} - {{date.close}}</p></ion-col>
<ion-col width-100 class="distance">
<p>{{store.dis | formatDistance}} <ion-icon name="pin"></ion-icon></p>
<p><a target="_blank" href="http://www.google.com/maps/place/{{store.obj.chain}} {{store.obj.location.address}}, {{store.obj.location.zip}} {{store.obj.location.city}}">Rutevejledning</a></p>
</ion-col>
</ion-col>
</ion-row>
</ion-card>
</accordion-heading>
<div class="extra-info">
<ion-grid>
<ion-row>
<ion-col width-100>
<p class="week">Uge {{weekNumber}}</p>
</ion-col>
</ion-row>
<ion-row width-100 *ngFor="let date of store.obj.openingDates | afterWhere: {date: tomorrow} | slice:0:leftInWeek">
<ion-col width-50 class="weekday">{{date.date | date: "EEEE, d MMMM"}}</ion-col>
<ion-col width-50 class="hours">{{date.open}} - {{date.close}}</ion-col>
</ion-row>
</ion-grid>
</div>
</accordion-group>
</accordion>
This all works fine, but what i then wish do to being able to filter the results by the "chain" property in the object so that i only get some chains (Walmart, Costco, etc.)
I just not sure how to handle this. In the Ionic provided navigation i have a collection of toggle switches for the different chain (they're hardcoded, don't worry) that i would like to use for the filtering:
Navigation toggles
<ion-content>
<ion-item>
<ion-label>Chain 1</ion-label>
<ion-toggle></ion-toggle>
</ion-item>
<ion-item>
<ion-label>Chain 2</ion-label>
<ion-toggle></ion-toggle>
</ion-item>
<ion-item>
<ion-label>Chain 3</ion-label>
<ion-toggle></ion-toggle>
</ion-item>
Initially i was hoping to use something like filterBy in Angular 2 version of ng-pipes but filterBy will only accept a single value to filter by and as such isn't really very useable in my scenario.
So what's the best option here? Some sort of custom filter pipe? and do i sort in the final object or do i pass some parameters to the api and limit before the data is sent back?
It's all a bit confusing, and this is my first Angular project so i'd really appreciate some guidance as to how i'll do this (in the best possible way)
Upvotes: 2
Views: 630
Reputation: 2862
I would solve this by, like you mentioned, querying the API. I'm not sure what the scale of your data is, but adding the filtering to your API makes your application more efficient at scale.
If you do not want to go that route, then I would look at pipes. They are an extremely useful tool to know how to use and create.
https://angular.io/docs/ts/latest/guide/pipes.html
The angular 2 docs has a guide on how to create a pipe. Check out the Flying Heroes pipe section. There is a plunkr for it here.
template
<div *ngFor="let hero of (heroes | flyingHeroes)">
{{hero.name}}
</div>
pipe
import { Pipe, PipeTransform } from '@angular/core';
import { Flyer } from './heroes';
@Pipe({ name: 'flyingHeroes' })
export class FlyingHeroesPipe implements PipeTransform {
transform(allHeroes: Flyer[]) {
return allHeroes.filter(hero => hero.canFly);
}
}
Once youve created the pipe, you can transform the data anyway you want in the transform method. In their example, they use the filter function, only returning heroes the canFly. In your case, you can replace the .canFly check with something like:
let wantedChains = ['Costco', 'Walmart', 'etc...']
transform(stores: Store[]) {
return stores.filter(store => (wantedChaines.indexOf(store.chain) > -1));
}
Upvotes: 1