0
votes

The one thing I'm finding in using observables in my Angular 2 app is that, because nothing actually "happens" until you subscribe to the observable in the component, that makes it a little tricky to refactor by moving logic into a service layer.

For instance, here is an example of a function that receives a sorting parameter, and then filters the data shown to the view accordingly. This uses an observable where subscription is happening in my components, like so:

onSortReceived(sort)
{
    if (sort === 'alphabetical')
    {
        this.filtersService.getByFilter(this.page, this.pagesize, this.body)
        .subscribe(resRecordsData => {
            this.records = resRecordsData;
            this.data = resRecordsData.data;
            this.data.sort((a, b) => a.name.last.localeCompare(b.name.last));
        },
        responseRecordsError => this.errorMsg = responseRecordsError);
    }
    else if (sort === 'reverse alphabetical')
    {
        this.filtersService.getByFilter(this.page, this.pagesize, this.body)
        .subscribe(resRecordsData => {
            this.records = resRecordsData;
            this.data = resRecordsData.data;
            this.data.sort((a, b) => b.name.last.localeCompare(a.name.last));
        },
        responseRecordsError => this.errorMsg = responseRecordsError);
    }
    else if (sort === 'id')
        {
        this.filtersService.getByFilter(this.page, this.pagesize, this.body)
        .subscribe(resRecordsData => {
            this.records = resRecordsData;
            this.data = resRecordsData.data;
            this.data.sort((a, b) => b._id.localeCompare(a._id));
        },
        responseRecordsError => this.errorMsg = responseRecordsError);
    }
    else if (sort === 'reset') {
        this.filtersService.getByFilter(this.page, this.pagesize, this.body)
        .subscribe(resRecordsData => {
            this.records = resRecordsData;
            this.data = resRecordsData.data;
        },
        responseRecordsError => this.errorMsg = responseRecordsError);
    }
}

Now, rather than have to repeat this code in each component that does this, I'd like to move much of this logic out to a service layer. But since the filtering is happening AFTER subscription, and subscription happens at the level of the component, I'm not sure how to do this. Is there a way I can filter first, and THEN subscribe to the observable? What would that look like? If I could do this I could move much of this code out to a service layer.

2
make use of the filter operator for observables - Rahul Singh
I would likely move all of this code into the services layer, understanding that this function would be subscribing to fetches that also exist in the services layer, and then you would call this function from your components, passing in the parameters as appropriate and getting back the returned final value. You could make this function return a promise, or even make this an Observable itself. - Stephen R. Smith

2 Answers

1
votes

How about something like this:

filter: any;
onSortReceived(sort)
{
    if (sort === 'alphabetical')
    {
        this.filter = (a, b) => a.name.last.localeCompare(b.name.last);
    }
    else if (sort === 'reverse alphabetical')
    {
         this.filter = (a, b) => b.name.last.localeCompare(a.name.last);
    }
    else if (sort === 'id')
    {
         this.filter = (a, b) => b._id.localeCompare(a._id);
    }
    else if (sort === 'reset') 
    {
           this.filter = undefined;
    }

    this.filtersService.getByFilter(this.page, this.pagesize, this.body)
    .subscribe(resRecordsData => {
        this.records = resRecordsData;
        this.data = resRecordsData.data;
        this.data.sort(this.filter);
    },
    responseRecordsError => this.errorMsg = responseRecordsError);
}

Then you could more readily move code into a service as needed.

NOTE: This code was not syntax checked or tested.

0
votes

Taking into account quote

is there a way I can filter first, and THEN subscribe to the observable

.map((response: Response) => response.json().data)
.filter(data => data.Type === 'myfilter')

or like this

.map(content => response.json().data)
.concatMap(arr => Observable.from(arr))
.filter(item => item.Type === 'myfilter')
.subscribe(val => console.log(val))