ghuntheur
ghuntheur

Reputation: 392

Stop observable stream of shared data service Angular

I have this service to share data between components of my application :

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

@Injectable()
export class DataService {

    private source = new BehaviorSubject<any>('');
    data = this.source.asObservable();

    constructor() { }

    update(values: any) {
        this.source.next(values);
    }
}

From a component, I update data like this :

this.dataSvc.update(this.data);

Assuming this.data is an object.

From another component, I subscribe at the service

this.dataSvc.data.subscribe(
    data => let object = data,
    error => console.log(error),
    () => console.log('complete')
);

The complete method is never called. How I can call the complete method and stop subscribing ?
I tried to add this.source.complete() just after next in service. It doesn't work

Thanks

Upvotes: 1

Views: 2219

Answers (1)

vince
vince

Reputation: 8306

The reason the Observable never completes is that you are never unsubscribing from it.

You could use an operator like takeUntil (if there is a certain condition you want to unsubscribe on), but I have a feeling you just need to clean up your subscription when the component is destroyed. Here are a couple options for how to do that:

You can use the ngOnDestroy lifecycle hook to unsubscribe from this subscription when the component is destroyed.

Try this:

subscription: Subscription;

/* using ngOnInit life cycle hook for the example, 
   but you could assign the subscription anywhere */
ngOnInit() { 
  this.subscription = this.dataSvc.data.subscribe( //.. )
}

ngOnDestroy() {
  this.subscription.unsubscribe();
}

The problem is that you are setting up your subscription, but never cleaning it up, so the Observable never "completes". The above code will fix that problem.

Alternatively, if you only need the data in your template and not in your component class, you could use the async pipe.

In your component.ts file:

data$: Observable<Data>;
ngOnInit() {
  this.data$ = this.dataSvc.data;
}

Then in your template:

 <p> {{ data$ | async }} </p>

When your component gets destroyed, Angular will handle all the clean up for you :)

Here are some links about life cycle hooks, the unsubscribe method, and the async pipe.

Upvotes: 3

Related Questions