3

I'm using Subscription to get a parameter from the route in angular. Here is the code:

import { Component, OnInit, OnDestroy } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Subscription} from 'rxjs'; @Component({ selector: 'farm-house', templateUrl: './house.component.html', styleUrls: ['./house.component.scss'] }) export class GreenhouseComponent implements OnInit, OnDestroy { private routeSub: Subscription; id: string; constructor(private route: ActivatedRoute) { this.id = ""; } ngOnInit(): void { this.routeSub = this.route.params.subscribe(params => { this.id = params['id']; }); } ngOnDestroy() { this.routeSub.unsubscribe(); } } 

But the problem is that the compiler says:

Property 'routeSub' has no initializer and is not definitely assigned in the constructor.

My question is, what is the best way to initialize a Subscription object?

5
  • 2
    put your ngOnInit code in to constructor Commented Nov 9, 2021 at 11:57
  • @RaviAshara Yeah thanks! this fixes the error but the thing is I'm new to angular so I'm not sure if it's totally ok to do that because in all other examples they subscribed in ngOnInit. Commented Nov 9, 2021 at 12:09
  • private routeSub: Subscription=null; Commented Nov 9, 2021 at 12:23
  • @Eliseo I've already tried it, but null is not assignable to Subscription. Commented Nov 9, 2021 at 12:56
  • private routeSub?: Subscription; it is implicitly undefined... no problem. ngOnDestroy() { this.routeSub?.unsubscribe(); } note the question mark it stops processing if undefined. Commented Feb 7, 2023 at 2:45

8 Answers 8

9

I've come up with another solution which is using Subscription.EMPTY from this question.

import { Component, OnInit, OnDestroy } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Subscription} from 'rxjs'; @Component({ selector: 'farm-house', templateUrl: './house.component.html', styleUrls: ['./house.component.scss'] }) export class GreenhouseComponent implements OnInit, OnDestroy { private routeSub: Subscription; id: string; constructor(private route: ActivatedRoute) { this.routeSub = Subscription.EMPTY; this.id = ""; } ngOnInit(): void { this.routeSub = this.route.params.subscribe(params => { this.id = params['id']; }); } ngOnDestroy(): void { if(this.routeSub) { this.routeSub.unsubscribe(); } } } 
Sign up to request clarification or add additional context in comments.

Comments

4

Should just be

private routeSub: Subscription = new Subscription

This is what worked for me.

Comments

1

Most of the cases it's should be enough to check the subscription before unsubscribe.

 ngOnDestroy() { if(this.routeSub) { this.routeSub.unsubscribe(); } } 

In your case, it's not required to initialize subscription because you already called subscribe method in ngOnInit(). Error might come because you are calling unsubscribe() directly on Subscription without checking it's initialized or not.

4 Comments

Even that checking is not convincing the compiler! There should be a value to initialize it with.
@eta32carinae You are already assigned value to it in ngOnInit right, but it’s okay to initialise value as ‘null’ while you declaring it.
I've already tried that but it says Type 'null' is not assignable to type 'Subscription'.ts(2322). It seems that moving the ngOnInit code to the constructor is the way to go. Thank you by the way.
you need 'private routeSub?: Subscription;' note the question mark.
0

Way 1:

Where I have a single subscription.

private routeSub?: Subscription; ngOnInit(): void { this.routeSub = this.route.params.subscribe(params => { this.id = params['id']; }); } ngOnDestroy(): void { // no need to do a separate if, use ? it is more readable this.routeSub?.unsubscribe(); } 

Way 2 where I have multiple subscriptions, I clean them all up with a single clean up:

 private destroyed$ = new Subject<boolean>(); Somewhere() { combineLatest([userService.spaceName$, userService.userName$]) .pipe(takeUntil(this.destroyed$)) .subscribe(([space, username]) => {do something...} } ngOnDestroy() { this.destroyed$.next(true); this.destroyed$.complete(); } 

third way - mostly the best way

myObservable$: Observable<myInterface>; ngOnInit() { this.myObservable$ = this.myservice.someObservable$; } ... html ... <ng-container *ngIf='myObservable$ | async as list; else simpleInput'> 

This last process works with onPush and you never forget to unsubscribe.

Note the first way is really handy when you subscribe and unsubscribe as part of the call, even combined with the second way:

pollUser(): void { // if it has been hear before unsubcribe, otherwise skip it. this.subscription?.unsubscribe(); this.subscription= this.someservice(serviceParameters) .pipe(takeUntil(this.destroyed$)) .subscribe(result => { this.useResult = result; }); } 

Comments

0

I just use:

private subscriptions: Subscription = new Subscription() 

During your code, you can then use:

this.subscriptions.add() 

And don't forget to unsubscribe:

ngOnDestroy() { this.subscriptions.unsubscribe() } 

Comments

-1

If you declare routeSub: any; the compiler shouldn't complain. source: saw it done in this post and i worked for me

1 Comment

My compiler shows a warning for defining types as any. You can see my solution here if you're interested.
-1

Unsubscribe is not needed here because Angular destroys this particular subscription for you.

2 Comments

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
github.com/angular/angular.io/issues/3003 -- this discusses that it is not required however it is good practice.
-1

Note that you can remove this error by adding "strictPropertyInitialization": false in you tsconfig.json

{ "compilerOptions": { "strictPropertyInitialization": false, } } 

Then you don't need to do this proper initialization, or add a second type undefined: private routeSub: Subscription | undefined

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.