kishore
kishore

Reputation: 396

Use returned subscribed data of an observable in a service from multiple component

I'm unable to get the returned data of my observable which is subscribed in service and the same is called in multiple components.

global.service.ts: 

sendProducts(){
   return this.getProducts().subscribe(response => {
     // perform some logic and return the output
      return data;
 });
}

getProducts(): Observable {
this.httpClient.get(this.apiUrl).pipe(map(resp => resp));
}

Now from multiple components, I want to access this data from my sendProducts() method and it is coming as undefined

products.component.ts

getProducts() {
   const productsList = this.globalService.sendProducts();
   console.log(productsList) => it is coming as undefined.
}

My required output is to get that returned data in components

Thanks in advance.

Upvotes: 1

Views: 901

Answers (2)

BizzyBob
BizzyBob

Reputation: 14750

The problem is that in your service, the sendProducts() method returns a Subscription rather than an Observable.

It is not necessary to subscribe in order to "perform some logic and return the output". You can instead use many different "pipeable operators" to transform the emitted values and run other code:

  • map - transforms data using the function you provide
  • tap - is for doing any type of "side-effect" type of logic. This does not affect what is returned
  • There are many, many, more operators for transforming, filtering, repeating, etc that you can use to suit your needs.

Service:

sendProducts() {
   return this.getProducts().pipe(
        tap(products => console.log('perform some logic...', products),
        map(products => ([...products, { id: 0, name: 'Default Product' }]))
   );
}

Then in your component: Component:

getProducts() {
   this.globalService.sendProducts().subscribe(
       productsList => console.log(productsList)
   );
}

But then how do you use that data (productsList) ?

You may be inclined to do something like this:

public products: Product[];

getProducts() {
   this.globalService.sendProducts().subscribe(
       productsList => this.products = productsList
   );
}

But you could get away with not subscribing at all, even in your component and do something like this:

public products$ = this.globalService.sendProducts();

Then in your template, use the async pipe to handle subscribing for you:

<ul>
  <li *ngFor="let product of products$ | async ">{{ product.name }}</li>
</ul>

The second approach results in less code :-)

Upvotes: 1

Stacks Queue
Stacks Queue

Reputation: 1152

  1. Your getProducts() should be the one to have the return
  2. Just call one function in your global.service.ts. Chances are the flow is asynchronous

Your getProducts() in global.service.ts should be:

getProducts() {
  return this.httpClient.get(this.apiUrl).pipe(map(resp => resp));
}

And you getProducts() in your product.component.ts

getProducts() {
  this.globalService.getProducts().subscribe(
     response => {
       console.log(response) //see your data here
     }, err => console.error(err)
  );
}

cleaner code and more understandable

Upvotes: 0

Related Questions