0

Below is a code sample that gives me results every 30 seconds, however, when a component subscribes to the service, it also has to wait 30 seconds for the initial set of data:

getTasks(query: string): Observable<any> {
  return this._http.get(this._ripcord + '/tasks' + query, this.getHttpOptions())
    .map((response: Response) => <any>response.json())
    .delay(30000)
    .repeat()
    .do(data => console.log(data))
    .catch(this.handleError);
}

I looked at a similar issue on stack but this solution doesn't work for me.

Does anyone know what operator I can use, in combination, to retrieve the initial data immediately on subscribe?

Cookie Monster
  • 636
  • 1
  • 12
  • 29
Andrew Lobban
  • 2,065
  • 2
  • 24
  • 38

4 Answers4

1

Thank you all for your responses as they helped me create my own solutions!

getTasks(query: string): Observable<any> {
  return Observable
    .timer(0, 30000)
    .switchMap(() =>
      this._http.get(this._ripcord + '/tasks' + query, this.getHttpOptions())
        .map((response: Response) => <any>response.json())
        .do(data => console.log(data))
        .catch(this.handleError)
    );
}

OR

getTasks(query: string): Observable<any> {
  return Observable
    .interval(30000)
    .startWith(0)
    .switchMap(() =>
      this._http.get(this._ripcord + '/tasks' + query, this.getHttpOptions())
        .map((response: Response) => <any>response.json())
        .do(data => console.log(data))
        .catch(this.handleError)
    );
}

OR

getTasks(query: string): Observable<any> {
  return Observable
    .timer(0, 30000)
    .switchMap(() =>
      this._http.get(this._ripcord + '/tasks' + query, this.getHttpOptions())
        .map((response: Response) => <any>response.json())

    )
    .do(data => console.log(data))
    .catch(this.handleError);
}

I realized I needed to utilize switchMap as map was returning an Observable in the subscription to the Http service GET response of the getTAsks endpoint. You can put the DO and the CATCH operators optionally on the switchMap instead of the map operator.

Andrew Lobban
  • 2,065
  • 2
  • 24
  • 38
0

interval.startWith (as referenced in the solution that you point to) is indeed the answer.

I suspect that what you really want is something like:

Observable
  .interval(30000)
  .startWith(0)
  .map(event =>
    this._http.get(this._ripcord + '/tasks' + query, this.getHttpOptions())
  )
  .do(data => console.log(data))
  .catch(this.handleError);
Andrew Lobban
  • 2,065
  • 2
  • 24
  • 38
GreyBeardedGeek
  • 29,460
  • 2
  • 47
  • 67
0

You could use timer. With timer you can specify when should emission start. Following sample emits first value immediately then it takes 5 secs to emit subsequent values.

var sourceTimer = Rx.Observable
        .timer(0, 5000)
        .timeInterval()
        .take(10);

var subscriptionTimer = sourceTimer.subscribe(
        function (x) {
            console.log('Next: ' + JSON.stringify(x));
        },
        function (err) {
            console.log('Error: ' + err);
        },
        function () {
            console.log('Completed');
        });

Output:

Next: {"value":0,"interval":4}
Next: {"value":1,"interval":5004}
Next: {"value":2,"interval":5000}

Interval & startWith also work, immediately emits the value zero which you provided as parameter to startWith then emits subsequent values in provided interval.

  var source = Rx.Observable
    .interval( 5000 /* ms */)
    .startWith(0)
    .timeInterval()
    .take(10);

 var subscription = source.subscribe(
    function (x) {
        console.log('Next: ' + JSON.stringify(x));
    },
    function (err) {
        console.log('Error: ' + err);
    },
    function () {
        console.log('Completed');
    });

Output:

Next: {"value":0,"interval":1}
Next: {"value":0,"interval":5003}
Next: {"value":1,"interval":5000}

Next: {"value":7,"interval":5000}
Next: {"value":8,"interval":5001}
nayakam
  • 4,149
  • 7
  • 42
  • 62
0

If you need to keep the observable sequence going when the http request returns an error catch the error when making the request and return an empty observable.

  getTasks(query: string): Observable<any> {
    return Observable
      .interval(30000)
      .startWith(0)
      .switchMap(event => {
        this._http
          .get(this._ripcord + '/tasks' + query, this.getHttpOptions())
          .catch(error => Observable.empty());
      })
      .map((response: Response) => <any>response.json())
      .do(data => console.log(data))
      .catch(this.handleError);
  }

Otherwise the sequence will stop on the first error.

JayChase
  • 11,174
  • 2
  • 43
  • 52
  • This option to me isn't clear to understand and it crashes my application with **TypeError: Cannot read property 'data' of undefined** – Andrew Lobban Dec 12 '17 at 15:17
  • @AndrewLobban you would have to be check for null being emitted and handle that. The important bit is that only having a catch on the end of the observable chain will mean that if the _http.get fails the observable will stop. By handling the error and then returning an observable it will keep on making the request every 30 seconds, – JayChase Dec 12 '17 at 23:51
  • Thanks! I did realize however the map wasn't returning my data object, but another observable, so I needed to merge the observables with switchMap. Hence the DO operator wouldn't have data to log. So if you see my solution, I remedied that. – Andrew Lobban Dec 13 '17 at 00:15
  • @AndrewLobban You're right sorry about that. I should have used switchMap not map. I've updated the answer. You can do the map after the switchMap and check is the response is null there – JayChase Dec 13 '17 at 02:56