0

In angular I have created a service that gets the data from different service and merge the data with the first service. Here is the code

searchData(): Observable<MyData> {
    const url = `${this.context}/search`;
    return this.http.get<MyData>(url)
        .pipe(
            map((myData: MyData) => {
                return this.secondService.getOtherData().subscribe((data) => {
                    // some manipulation
                    return myData;
                });
            }));
}

but this is showing the error

Type 'Observable<Subscription>' is not assignable to type 'Observable<MyData>'.
  Type 'Subscription' is missing the following properties from type 'MyData': data, dataCount

How can i solve this?

Apoorva Chikara
  • 8,277
  • 3
  • 20
  • 35
Sunil Garg
  • 14,608
  • 25
  • 132
  • 189
  • 1
    two issues. Subscribe doesn’t return anything and if you are trying to return an inner observable you need to use something like switchMap or mergeMap – Alexander Staroselsky Aug 20 '21 at 05:06

3 Answers3

3

You are almost there. RxJS operator map is used to manipulate the emitted data from an observable and forward it.

Option 1: dependent observables

To map from one observable to another, you'd need to use a higher order mapping operator like switchMap.

searchData(): Observable<MyData> {
  const url = `${this.context}/search`;
  return this.http.get<MyData>(url).pipe(
    switchMap((myData: MyData) =>         // <-- `switchMap` here
      this.secondService.getOtherData().pipe( // <-- assuming `getOtherData()` depends on response from 1st call
        map((data: any) => {              // <-- `map` here
          // some manipulation
          return myData;
        })
      )
    )
  );
}

Option 2: independent observables

If the observables do not depend on each other, you could use something like RxJS forkJoin function to trigger the observable in parallel.

searchData(): Observable<MyData> {
  const url = `${this.context}/search`;

  return forkJoin({
    myData: this.http.get<MyData>(url),
    secondData: this.secondService.getOtherData().pipe(  // <-- assuming `getOtherData()` doesn't depend on response from 1st call
      map((data: any) => {
        // some manipulation
        return manipulatedData;
      })
    )
  });
}

In this case you'd get both the responses in the subscription.

this.searchData().subscribe({
  next: (res: any) => {
    // res.myData
    // res.secondData
  },
  error: (error: any) => {
    // handle error
  }
});

See here for more information on avoiding nested subscriptions.

ruth
  • 29,535
  • 4
  • 30
  • 57
0

You have to modify map to switchmap.

searchData(): Observable<MyData> {
    const url = `${this.context}/search`;
    return this.http.get<MyData>(url)
        .pipe(
            switchMap((myData: MyData) => {
                return this.secondService.getOtherData().subscribe((data) => {
                    // some manipulation
                    return myData;
                });
            }));
}
N.F.
  • 3,844
  • 3
  • 22
  • 53
0

This is because your function return type is Observable<MyData> and in the map function you are returning a subscription


    searchData(): Observable<MyData> {
        const url = `${this.context}/search`;
        return this.http.get<MyData>(url).pipe(
             switchMap((myData: MyData) => this.secondService.getOtherData())
        );
    }

you have to subscribe to searchData() method which will subscribe to outer and inner observables. You can use tap operator to get data from these apis separately.


    searchData(): Observable<MyData> {
        const url = `${this.context}/search`;
        return this.http.get<MyData>(url).pipe(
             tap(myData => console.log(myData)),
             switchMap((myData: MyData) => this.secondService.getOtherData()),
             tap(otherData => console.log(otherData))
        );
    }

JsNgian
  • 795
  • 5
  • 19