Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rxjs - resubscribe to unsubscribed Observable

I'm using a Service to "ping" my server every 2.5s, returning the response time from my server. Therefore I am using observables.

I am also using angular 2 and typescript.

I now want to stop the service (unsubscribe) on button click. This works just fine! The button should be a togglebutton, so if not subscribed, subscribe and other way around. But resubscribing doesn't work!

Here is my service:

export class PingService {
  pingStream: Subject<number> = new Subject<number>();
  ping: number = 0;
  url: string = url.href;

  constructor(private _http: Http) {
    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);
          });
      });
  }
}

And here is my function on click:

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

I am subscribing to the PingService within the cunstructor of my appcomponent. The data gets displayed in a chart. When I click the button for the first time, it stops the service, no data updates anymore. When I click the next time, nothing happens, although the "this.pingService.pingStream.isUnsubscribed" returns true.

my constructor:

    constructor(private location: Location,
       private pingService: PingService) {

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

I am also getting an error "ObjectUnsubscribedError" when I click the button for the first time.

Any help is appreciated! Thanks!

like image 369
Faigjaz Avatar asked Aug 15 '16 06:08

Faigjaz


People also ask

What happens if you don't subscribe to an Observable?

Remember, observables are lazy. If you don't subscribe nothing is going to happen. It's good to know that when you subscribe to an observer, each call of subscribe() will trigger it's own independent execution for that given observer. Subscribe calls are not shared among multiple subscribers to the same observable.

What happens if you don't unsubscribe from an Observable?

As you probably know when you subscribe to an observable or event in JavaScript, you usually need to unsubscribe at a certain point to release memory in the system. Otherwise, you will have a memory leak.

How do I unsubscribe from Observable RxJS?

Unsubscribing Manually One method we can use, is to unsubscribe manually from active subscriptions when we no longer require them. RxJS provides us with a convenient method to do this. It lives on the Subscription object and is simply called . unsubscribe() .

Does TakeUntil unsubscribe?

We can simply call the unsubscribe() method from the Subscription object returned by the subscribe() method in the ngOnDestroy() life-cycle method of the component to unsubscribe from the Observable. There is also a better way to unsubscribe from or complete Observables by using the takeUntil() operator.


1 Answers

Since you are using RxJS you don't have to subscribe/unsubscribe. Just consider another approach using Rx streams. The idea is to have 2 streams main and toggle stream, so combined they fire events only when your toggle stream is on.

var mainStream = Rx.Observable.interval(100).map(() => '.');

var display = document.getElementById('display');
var toggle = document.getElementById('toggle');

var toggleStream = Rx.Observable
  .fromEvent(toggle, 'change')
  .map(e => e.target.checked);

var resultStream = toggleStream
  .filter(x => x === true)
  .startWith(true)
  .flatMap(() => mainStream.takeUntil(toggleStream));

resultStream.subscribe(x => display.innerText += x);
<!DOCTYPE html>
<html>

  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.1.0/rx.all.min.js"></script>
  </head>

  <body>
    <input type="checkbox" id="toggle" checked> Check/uncheck to start/stop
    <div id="display"></div>
    
    <script src="script.js"></script>
  </body>

</html>
like image 78
Max Brodin Avatar answered Oct 14 '22 15:10

Max Brodin