0

I have a component which has a method interval(), when a button is clicked.

 interval() {
    this.statusInterval = interval(2000).subscribe(x => {
      this.interval2 = x;
      console.log(this.interval2);
      this.assetItemActionService.sendNumber(x);
    })
  }

In constructor I have this subscription which should update that value.

 interval2 = 0;
 percentSubscription= Subscription;
  constructor(private service:Service) {
    console.log('takeee');
    this.percentSubscription = this.service.number$.subscribe(percent => {
      console.log("set number");
      this.interval2 = percent;
    }, error => console.log(error))
  }

The up 2 code fragments are in the same component.

In service I have this subject which is updated constantly.

private number: Subject<number> = new Subject();
number$ = this.number.asObservable();

  sendNumber(number) {
    console.log('received');
    this.number.next(number);
  }

The problem is when I route to another page, the UI is not updated, and the part from constructor is not working anymore, I can't subscribe, but in console the value is updated every time. So the UI is not rendered, and I can't subscribe anymore to that subject after I come back on component.

How I can solve this?

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
Alex Alexa
  • 107
  • 9

1 Answers1

1

You should unsubscribe the subscription(s) that you have in the component.

The fact that you're still able to see logs on your console after leaving the component clearly indicate that you haven't unsubscribed from the subscriptions, which in turn is causing memory leaks.

Here, give this a try:

import { Component, OnInit } from "@angular/core";
import { Subscription, interval } from "rxjs";

import { NumberService } from "../number.service";

@Component({
  selector: "app-some",
  templateUrl: "./some.component.html",
  styleUrls: ["./some.component.css"]
})
export class SomeComponent implements OnInit {
  interval2 = 0;
  percentSubscription = Subscription;
  statusInterval;

  constructor(private assetItemActionService: NumberService) {
    console.log("takeee");
    this.percentSubscription = this.assetItemActionService.number$.subscribe(
      percent => {
        console.log("set number");
        this.interval2 = percent;
      },
      error => console.log(error)
    );
  }

  ngOnInit() {
    this.interval();
  }

  interval() {
    this.statusInterval = interval(2000).subscribe(x => {
      this.interval2 = x;
      console.log(this.interval2);
      this.assetItemActionService.sendNumber(x);
    });
  }

  ngOnDestroy() {
    this.percentSubscription.unsubscribe();
    this.statusInterval.unsubscribe();
  }
}

PS: You didn't specify what you're using in the template. So I've just added the routes to two components(some, and hello).


Here's a Working Demo for your ref.

SiddAjmera
  • 38,129
  • 5
  • 72
  • 110
  • Hi thank you for blitz, but my issue is that, I want to let interval run, while I am doing something else on another page, than come back on the page with interval and 'interval2' counter and to display the current number. Add this code in your some.html to see counter : https://stackblitz.com/edit/subscriptions-causing-memory-leaks-solved-bs4j71?file=src/app/some/some.component.html . Or if there is any other approach :) – Alex Alexa Dec 12 '19 at 15:04
  • 1
    The interval should then be in the service and not in the component. If you navigate away from the component via routing, it will destroy. When you come back, a new instance of the component will get created and it will have a new subscription. So keeping the interval in the component will reinitialize it which is not what you want. Keeping the interval in the service will retain the current value on it and will not reinitialize the component again and again. – SiddAjmera Dec 12 '19 at 15:09
  • Thank you! And in component I think i should do a getter to retrive that value from a variable or behavioursubject,right? – Alex Alexa Dec 12 '19 at 15:20
  • 1
    Just assign the interval from the service's subject to a property on the component. And then use it in the template via an `async` pipe. That way, you won't have to explicitly unsubscribe and you would still avoid memory leaks. – SiddAjmera Dec 12 '19 at 15:36