4

I have two components using the same service. On FirstComponent, I get some data from a service:

getLiveData() {
  Observable.interval(1000)
    .mergeMap(() => this.service.getData())
    .subscribe(
      res => this.data = res,
      err => this.error = err
    );
}

At first, I've added another getLiveData() to the SecondComponent. However, that way I'm making two REST calls every second. That shouldn't be needed as I want to use the same service.

So, can I reuse that in the SecondComponent without making two calls every time?

I tried to add the FirstComponent as a service and called this.service.data but I'm getting undefined.

PS. I also need the values to be updated every second on both components.

UPDATE: I've posted a Plunker following Madhu's advice. I managed to get only one call per time, but I'm not getting any data from it.

brians69
  • 485
  • 2
  • 11
  • 24
  • 2
    http://stackoverflow.com/questions/36271899/what-is-the-correct-way-to-share-the-result-of-an-angular-2-http-network-call-in – Günter Zöchbauer Sep 29 '16 at 15:48
  • 1
    Please check the answers on this question. I think this might be helpful to you. http://stackoverflow.com/questions/34104277/caching-results-with-angular2-http-service – gdyrrahitis Sep 29 '16 at 15:51
  • @GünterZöchbauer It didn't work for me. When I use `Observable.interval`, it keeps calling the service twice. :/ – brians69 Sep 29 '16 at 16:43
  • Hard to know what exactly you're doing. – Günter Zöchbauer Sep 29 '16 at 16:53
  • @GünterZöchbauer I guess your method only calls the data again if it's not in the cache, right? For my case, I need it to make a call to the network every 1s. Using your method, it calls the network only when the app starts: http://plnkr.co/edit/F3E8uPnhXM08ptf6iGNz?p=preview - after that, it calls every 1s but only the cache data. – brians69 Sep 29 '16 at 18:08
  • You can clear the cache every second, then it calls to the server again if it can't find the data in the cache. – Günter Zöchbauer Sep 29 '16 at 18:13
  • I'm not sure that would solve the problem. In the Plunker above, the `getData()` is called twice every time. So, it would probably make two network requests as well, right? – brians69 Sep 29 '16 at 18:43

2 Answers2

2

You can try to move the interval to the service.

observableSub;
getDataObservable() {
    if (!this.observableSub) {
        this.observableSub = Observable.interval(1000)
            .mergeMap(() => this.getData())
    } 
    return this.observableSub;
}

And on the component:

getLiveData() {
  this.getDataObservable().subscribe(
      res => this.data = res,
      err => this.error = err
    );
}
Guilherme Meireles
  • 7,849
  • 2
  • 21
  • 15
1

You may try below,

@Injectable()
export class MyAwesomeService{
  _streamingData: Subject<any> = new Subject<any>();
  streamingObservable = {};

  get streamingData$(){
    return this._streamingData.asObservable();
  }      

  getLiveData(){
    if(!!this.streamingObservable){
    const start = 10;
    this.streamingObservable =  Observable
         .interval(1000)
         .mergeMap(() => this.service.getData())
         .subscribe(
            res => {
              this._streamingData.next(res);
            },
            err => {
              console.log(err);
            }
         );
    }
    return this.streamingObservable;
  }
}

@Component({
  selector: 'my-app',
  template: `<h3>Live streaming data</h3>
   <hr />
   <child-comp-1></child-comp-1>
   <hr />
   <child-comp-2></child-comp-2>
  `
})
export class AppComponent { }

@Component({
  selector: 'child-comp-1',
  template: `<h3>Child component</h3>
   Streaming Data: {{ data | async }}
  `
})
export class ChildComponent1 {
  data = "Hello!!";
  constructor(private myservice:MyAwesomeService){
    this.data= myservice.streamingData$;
    myservice.getLiveData();
  }
}

@Component({
  selector: 'child-comp-2',
  template: `<h3>Child component 2</h3>
   Streaming Data: {{ data | async }}
  `
})
export class ChildComponent2 {
  data = "Hello!!";
  constructor(private myservice:MyAwesomeService){
    this.data= myservice.streamingData$;
  }
}

Here is the Plunker!!, In Plunk i have simulated service data with a simple map which gives data at an interval.

Update

Plunker with consuming API using Http.

Hope this helps!!

Madhu Ranjan
  • 17,334
  • 7
  • 60
  • 69
  • Thanks, @MandhurRanjan. Do you know how I can use that with an `HTTP` call? If I try to `map` the `URL` I get an error: `argument is not a function. Are you looking for mapTo()?`: http://plnkr.co/edit/0fl79aTUBMgwk00ujgJy?p=preview – brians69 Sep 29 '16 at 18:40
  • I managed to get only one call per time, but I'm not getting any data from it. I've updated the Plunker: http://plnkr.co/edit/lTnKkqn7VMTflQE09kOL?p=preview – brians69 Sep 29 '16 at 19:06
  • 1
    Check out this [Plunker](http://plnkr.co/edit/I9ewCITuVZTvRLTuz6LN?p=preview), Cheers!! – Madhu Ranjan Sep 29 '16 at 19:11
  • @drbishop: Note in one component i have added a json pipe so that you may see json response. – Madhu Ranjan Sep 29 '16 at 19:13
  • Thanks, @MadhuRanjan! I own you a beer! =) btw, I didn't know that `jsonplaceholder` website. It's very useful to try out those things. – brians69 Sep 29 '16 at 19:19
  • Glad I could be of help!! – Madhu Ranjan Sep 29 '16 at 19:30
  • One more thing: do you know why I'm not able to retrieve the values inside the `json` (i.e. `{{data.id}}`)? http://plnkr.co/edit/AuGDmHkfVv0ZD9AOCjCN?p=preview – brians69 Sep 29 '16 at 19:45
  • 1
    check this [Plunker](http://plnkr.co/edit/hfPQVtH2WPk8Cc9z5Sl9?p=preview)!! – Madhu Ranjan Sep 29 '16 at 19:51
  • Oh, I was forgetting to subscribe haha. Thanks, again. – brians69 Sep 29 '16 at 19:54