Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use a filter or pipe to load product categories into pages in Ionic 2?

I wish to create a Ionic 2 app with 6 pages, I am unsure whether to use a Pipe or a Filter for the individual category pages and the code I need to do that.

Each category page can load the relevant products defined by the "applecat" category. Below is the API, display of the products in spreadsheet format via Google Sheets and a very quick homepage mockup idea:

https://sheetsu.com/apis/v1.0/04c2d2906a10 https://docs.google.com/spreadsheets/d/1RNLXsxTFymqRwq_S538qX1p1PAEDIEA6s5sV8etkfLU/edit?usp=sharing

enter image description here

OVERVIEW

6 pages

  • home - no products needed to load - just links to pages
  • allproducts -loads ALL products
  • ipad - loads all items listed as ipad under applecat category
  • iphone - loads all items listed as iphone under applecat category
  • keyboard - loads all items listed as iphone under applecat category
  • laptop -loads all items listed as iphone under applecat category

SCENARIO (Potential user flow)

User opens app, clicks on Home then Ipad category link (Loads all Ipad products) then comes back to Home decides to click on All (Loads ALL products), the back and clicks on another page....

PROBLEM

Will it load 2 arrays into memory/console? Should the category pages use a filter or a pipe? How should the code look for the pipe/filter in relation to my existing API call and product list array?

PROVIDERS

getRemoteData(): any{
        return this.http.get('https://sheetsu.com/apis/v1.0/04c2d2906a10')
                .map(res => res.json());
}

LIST PAGE

@Component({
selector: 'page-master',
templateUrl: 'master.html',
providers: [Sheetsu]
})
export class MasterPage {

// declare publicly accessible variable
public sheetsuData: any;

constructor(public navCtrl: NavController, public navParams: NavParams, public sheetsuService: Sheetsu) {}

ionViewDidLoad() {
    this.sheetsuService.getRemoteData()
    .subscribe(response => {
    // assign variable (async)
    this.sheetsuData = response;
    });
}

I saw an example of filter with resets but not sure whether that is applicable in this situation?

 resetData(){
    this.modifiedData = JSON.parse(JSON.stringify(this.originalData));
  }

  filterData(){
    this.modifiedData = this.modifiedData.filter((youtuber) => {
        return youtuber.subscribers > 1000000;
    }
  }

With so few category pages, perhaps a Pipe would be the best option for each page? Just the potential problem of multiple API calls if the users browse all 6 pages.

Preferred bounty answer : Code for pipe/filter/service, advice on best solution and why, even better a basic working example in Github (API call for Provider and list ts code is above).

Github repo for this can be viewed and forked from https://github.com/jones98/4cat

Video of app in present state (pre-category pages working) can be viewed at https://drive.google.com/file/d/0B0QBawqyq1vPZ0o4WEpaa0o0azQ/view

like image 862
me9867 Avatar asked Feb 09 '17 14:02

me9867


1 Answers

You can create a service that caches the data (maybe for 5 minutes, 30 minutes, one hour, or any time interval that makes sense in the context of your application) in order to avoid making so many http request, and will also return only what you need so you can use it directly in the component/view, without filtering anything.

This will not only save a lot of useless http requests being made to the server, but it will also make the app way faster since local data is going to be used most of the times the user opens the product pages.

Let's assume you already have a class for the products:

export class ProductModel {
    public aw_deep_link: string;
    public product_name: string;
    public apple_cat: string;
    //...
}

Then we can create our cache model like this:

class ProductCache {
    public products: Array<ProductModel>;
    public timestamp: number;

    public isValid(): boolean {
        if(!this.products) {
            return false;
        }

        let isExpired = Date.now() - this.timestamp > 1800000; // 30 min
        return !isExpired;
    }
}

and then we can use it in our ProductCategoryService

// Angular imports
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';

// Rxjs imports
import { Observable } from 'rxjs';
import 'rxjs/add/operator/map';

@Injectable()
export class ProductCategoryService {

    private cache: ProductCache;
    private apiUrl: string = 'https://sheetsu.com/apis/v1.0/04c2d2906a10';

    constructor(private http: Http) {
        this.cache = new ProductCache();
    }

    public getAll(): Observable<Array<ProductModel>> {
        if(this.cache.isValid()) {
            // Return the products from the cache
            return Observable.of(this.cache.products);
        }

        // Cache is empty/expired, so we need to make the http request
        return this.http.get(this.apiUrl).map(res => res.json()).map(data => {
            // Save the data in the cache for the next time
            this.cache.products = data;
            this.cache.timestamp = Date.now();

            // Return the list of (all) products
            return this.cache.products;
        });
    }

    public getIpadProducts(): Observable<Array<ProductModel>> {
        return this.getAll().filter((product: ProductModel) => {
            return product.apple_cat.toLowerCase() === 'ipad';
        });
    }

    public getIphoneProducts(): Observable<Array<ProductModel>> {
        return this.getAll().filter((product: ProductModel) => {
            return product.apple_cat.toLowerCase() === 'iphone';
        });
    }

    // ...
}

And then just call the right method in each page, and an http request will be made only once (or every 30 min in this example) because of the product's cache.

There could be syntax errors or typos (I coded directly in the SO answer) but this should give you the idea about how to deal with the given scenario. Please let me know if something doesn't work properly, so I can help you fixing it...

UPDATE: Here you can find some information (from Angular 2 Docs) about why using pipes to filter data is not a very good approach, and this is why I recommend doing that in the service, keeping it hidden to the rest of the application (after all, each category page just wants to get the data that it needs to show, it shouldn't have to deal with all the products to then find only the ones it needs to display in the view).

like image 139
sebaferreras Avatar answered Nov 19 '22 12:11

sebaferreras