Hassan
Hassan

Reputation: 2408

Manipulate data before returning observable

I am pretty new with Angular 2 and the concept of Observables. However what i am trying to achieve should be fairly simple for experienced gurus :)

So: I have a component in which i have subscribed the observable which is coming from a service. For testing purposes, i have been using data Arrays to make my components live. Now that when its done, i want to hook real API calls to my service. Now the problem is that the data that i get from the server needs to be manipulated before its returned to the component. When i manipulate it, i get error such as "cannot read property 'subscribe' of null"

Now basically this error is coming because in my service observable, i send an API request using HTTP.get method and the code doesn't wait for its response to finish. I do get the result from server but that comes after the error in console.

Can anyone please guide me how to request an HTTP call and then manipulate its data before sending it to the component that has the services subscribed?

Here is my component code:

getSearchResults(keyword, parentId?, subCatId?) {
    this.subscriptionResults = this.catalogService.getSearchResults(keyword, parentId, subCatId)
        .subscribe(
            data => {
                this.results                = data.results.parts;
                this.numResults             = data.results.totalItemCount;
                this.timeResults            = data.results.processingTimeMS;
                this.categories             = data.categories;
                this.subCategories          = data.subCategories;
                this.brands                 = data.brands;
                this.suppliers              = data.suppliers;
                this.layoutType             = data.layoutType;
                this.allCategories          = data.allCategories;
                this.selCategoryName        = data.selCategoryName;
                this.selSubCategoryName     = data.selSubCategoryName;

                if ( this.debugMode ) {
                    console.log('RESULTS: ', data);
                }
            },
            error => this.errorMessage = <any>error
        );
}

And here is my service:

// Get data from server
getDataFromServer(URL: string): Observable<any> {
    return this.http.get(URL).flatMap(this.extractData).catch(this.handleError);
}


getSearchResults(keyword: string, parentCatId?:number, subCatId?:number): Observable<any> {

    let request = null;
    let result  = null;

    let URL = this.API_URL + '/search?categoryId=' + subCatId + '&format=json';
    request = this.getDataFromServer(URL);

    request.subscribe(
        () => { 
            // Modify result here and send it back 
        },
        error => { console.log('ERROR: ', <any>error); }
    );

I want to manipulate the response data before i want to return it. How can i do that?

-- EDIT -- If i return a BehaviorSubject:

return new BehaviorSubject<any>(request.subscribe(
            res => { return this.processResultData(res, layoutType, keyword, parentCatId, subCatId); },
            err => { console.log('RETURN ERROR: ', <any>err); }
        ));

I get subscription object in my component (which is what i dont need). Instead i need the data thats inside of the subscription.

Upvotes: 16

Views: 17992

Answers (2)

dhilt
dhilt

Reputation: 20744

In addition to the accepted answer, since pipable operators (RxJs v5.5) it should be written as

import { map, catchError } from 'rxjs/operators';

and then

  return this.getDataFromServer(URL).pipe(
      map((response) => {
        // Modify response here
      }),
      catchError(error => console.log('ERROR: ', error))
  );

Upvotes: 16

Alex Wheeler
Alex Wheeler

Reputation: 335

Your component is subscribing to the return value from getSearchResults() so that function needs to return an Observable. Your getDataFromServer() function returns an observable, so what you can do is use Observable.map() on that return value. Observable.map() lets you modify the value moving through an observable stream, and return a new observable of the modified value. That new observable is the one your component will want to subscribe to, so that is what should be returned.

In code, it would look like:

getSearchResults(keyword: string, parentCatId?:number, subCatId?:number): Observable {

    let request = null;
    let result  = null;

    let URL = this.API_URL + '/search?categoryId=' + subCatId + '&format=json';
    return this.getDataFromServer(URL).map(
        (response) => {

            // Modify response here

            // Return modified response
        }
    ).catch((error) => { console.log('ERROR: ', error); });
}

When your component subscribes, it should see the modified response that comes from the .map().

Upvotes: 18

Related Questions