Faigjaz
Faigjaz

Reputation: 838

Change observable interval through input

I am using a service which "pings" my server and returns the response time. I then display this in a chart.

My first approach (without being able to change intervals) was this:

Observable.interval(2500)
        .subscribe((data) => {
          let timeStart: number = performance.now();

          this._http.get(this.url)
            .subscribe((data) => {
              let timeEnd: number = performance.now();

              let ping: number = timeEnd - timeStart;
              this.ping = ping;
              this.pingStream.next(ping);
            });
        });
}

This gets called in my app.component cunstructor:

this.pingService.pingStream.subscribe(ping => {
         this.ping = ping;
         NTWDATA.datasets[0].data.pop();
         NTWDATA.datasets[0].data.splice(0, 0, this.ping);
      })

I'm getting the "ping" and put it into my chartdata. Works fine. Now I want to change the intervall. Therefore I created a streamintervall.ts which is only exporting a variable called INTVL. I tried to use the answer in this post : Change Intervall/settings of observable after creation

So now I'm at this state, which doesn't work. My chartdata is counting from 0 on.

   observable = this.pingStream.startWith(INTVL)
   .switchMap((INTVL) => { return Observable.interval(INTVL) });
       constructor(private _http: Http) {
          this.observable.map((data) => {
             let timeStart: number = performance.now();
             this._http.get(this.url)
                .subscribe((data) => {
                   let timeEnd: number = performance.now();
                   let ping: number = timeEnd - timeStart;
                   this.ping = ping;
                   this.pingStream.next(ping);
                });
          })

In my appcomponent I have an input-textbox with a 2way binding to intvl = INTVL. I really don't know how to deal with this, because rxjs is kind of hard to get into and I am not really that experienced neither, so any detailed help would be appreciated very much.

If you need more information, tell me.

EDIT: Second approach - I am now creating a new Stream on button click with the input interval : pingservice.ts:

createNew(intvl: number) {
      this.pingStream = new Subject<number>();
      Observable.interval(intvl)
        .subscribe((data) => {
          let timeStart: number = performance.now();
          this._http.get(this.url)
            .subscribe((data) => {
              let timeEnd: number = performance.now();
              let ping: number = timeEnd - timeStart;
              this.ping = ping;
              this.pingStream.next(ping);
            });
        });
   }

app.component.ts:

newSubscription() {
      console.log(this.pingService.pingStream.isUnsubscribed);
      if (!this.pingService.pingStream.isUnsubscribed) {
         this.pingService.pingStream.unsubscribe();
      }
      if (this.pingService.pingStream.isUnsubscribed) {
         this.pingService.createNew(this.intvl)
         this.pingService.pingStream.subscribe(ping => {
            this.ping = ping;
            NTWDATA.datasets[0].data.pop();
            NTWDATA.datasets[0].data.splice(0, 0, this.ping);
         })
      }
   }

So, stopping the pingService works, the new Stream gets created and uses the correct intervall. Now I have another issue: When subscribing to pingStream after creating the new one, I also subscribe to every other pingStream created before (or at least I think I do), which leads into multiple streams delivering my data. 5 clicks = 5 streams. Is there a way to "destroy" those streams and create a new one after?

Upvotes: 1

Views: 1057

Answers (1)

j2L4e
j2L4e

Reputation: 7050

One way to do it would be using a Subject to emit the wanted interval and then use a combination of switchMap and flatMap. You can pause pinging by unsubscribing from interval$. To resume pinging resubscribe and call setInterval again. Or use a BehaviorSubject.

interval$: Subject<number> = new Subject<number>();

constructor(){
  this.interval$
    .switchMap((int: number) => Observable  //switch to Observable with new interval
      .interval(int)
      .flatMap(() => StreamOfPings) //execute time measurement function
    )
    .subscribe(res => console.log(res));
}

setInterval(newInterval: number){
  this.interval$.next(newInterval);
}

Upvotes: 1

Related Questions