Reputation:
I would like to stop observable, which one was created by share operator.
My service:
private timer = interval(1000).pipe(take(60), share());
private timerStarted = false;
startTimer() {
this.timer.pipe(
tap(() => this.timerStarted = true),
finalize(() => this.timerStarted = false)
).subscribe();
}
getTimer() {
return this.timer;
}
getTimerStarted() {
return this.timerStarted;
}
My component:
private destroy$ = new Subject<boolean>();
ngOnInit() {
if (this.timerService.getTimerStarted()) {
this.timerService.getTimer().pipe(
takeUntil(this.destroy$),
).subscribe();
}
}
onStartTimer() {
this.timerService.startTimer();
this.timerService.getTimer().pipe(
takeUntil(this.destroy$),
).subscribe();
}
ngOnDestroy() {
this.destroy$.next(true);
}
I tried add to service stop method:
stopTimer() {
this.timer.unsubscribe();
}
And use it in ngOnDestroy:
ngOnDestroy() {
this.destroy$.next(true);
this.timerService.stopTimer();
}
I would like stop the creating value in the background.
Upvotes: 1
Views: 1103
Reputation: 29335
you need to not create the subscription in your service, it's unclear why you're doing this. share() will naturally terminate once it has no subscribers left, but in the service, you're ensuring one subscriber always exists. just do this instead:
export class TimerService {
timer$ = interval(1000).pipe(
take(60),
tap(() => this.timerStarted = true),
finalize(() => this.timerStarted = false),
share());
private timerStarted = false;
getTimerStarted() {
return this.timerStarted;
}
}
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ],
providers: [TimerService]
})
export class AppComponent {
name = 'Angular';
sub;
constructor(private timer: TimerService) {
this.sub = this.timer.timer$.subscribe(v => console.log(v));
setTimeout(() => this.sub.unsubscribe(), 4000)
}
}
in the logs you'll see that the timer emits 4 times then stops after the timeout unsubscribes. You could just as easily unsubscribe in onDestroy hook or use the destroy$ emission method. both will have the same effect.
blitz: https://stackblitz.com/edit/angular-9a9bkl?file=src/app/app.component.ts
edit based on comments:
since you do want to keep a subscription alive between components, you need to modify your service to allow you to end that subscription:
private timer = interval(1000).pipe(take(60), takeUntil(stopTimer$), share());
private timerStarted = false;
private stopTimer$ = new Subject();
startTimer() {
this.timer.pipe(
tap(() => this.timerStarted = true),
finalize(() => this.timerStarted = false)
).subscribe();
}
stopTimer() {
this.stopTimer$.next();
}
this method will end the service level subscription and all others because the takeUntil is part of the timer pipe itself.
Upvotes: 1
Reputation: 492
Call the complete
method on the Unsubscribe Subject. Then the observable should automatically be destroyed when the ngOnDestroy
lifecycle calls.
ngOnDestroy() { this.destroy$.next(true); this.destroy$.complete();}
Edit:
For the timer
subscription store it a property within the service
this.subscription = <your observable>. subscribe()
stopTimer(){ this.subscription.unsubsribe();}
Then in the onDestroy
you can call the stopTimer
method.
Upvotes: 1