Why am I getting a "Cannot access 'variable' before initialization" error from a subscriber referencing itself?
You could get rid of this error by declaring sub
as an attribute of the component.
sub: Subscription = new Subscription();
// ...
constructor(public contentService: ContractService) {
let self = this;
this.sub = contentService.loaded.subscribe(function(loaded) {
// ...
this.sub.unsubscribe();
// ...
});
}
Although I need to say the proper place to do this kind of calls is not in the constructor. Maybe inside the ngOnInit
is a good place.
To make sure the subscriber do not receive any other values once the service returns the first one, you can indeed unsubscribe after its "job" is done (like you were doing), but declare the sub
variable as an attribute and initialize it with new Subscription();
To make sure you don't leave any subscription hanging you can unsubscribe from it in ngOnDestroy
in the component:
ngOnDestroy() {
// ...
this.sub.unsubscribe();
// ...
}
Additionally if you feel you need a better understanding of how the Observables pattern works see Angular Docs for Observables
You are checking for sub
before you've set sub
.
If you view your code logically, and set by step, you'll see that you are declaring sub
with an initial value. However, that initial value is a function, or specifically in this case a subscription. Which is still fine.
However - the issue lies in the fact, that in the function itself, you rely on the sub
variable being set. Which it isn't, because you're in the process of setting it, during its declaration.
Hence the error:
Cannot access 'sub' before initialization
It's actually unclear as to what you're trying to do, because logically it looks like you're trying to subscribe to something, but if your subscribed to it, unsubscribe? But you shouldn't do that in the unsubscribe.
If you would prefer, you could change your code to the following,
// I assume you have a variable "loaded" above, because you've set self to this in your code
private unsubscribeStream = new Subject();
this.contentservice.loaded.pipe(
filter(x => x !== null), // Filter out where x doesn't exist
takeUntil(this.unsubscribeStream)).subscribe(loaded => {
this.loaded = loaded;
});
// When the component is destroyed, call the next value of unsubscribe stream which will unsubscribe from anything we've set to takeUntil
ngOnDestroy() {
this.unsubscribeStream.next();
}
I just came across the same issue realizing that my code was old and written when I didnt know as much about rxjs, jet. I now see it as an antipattern to write code this way.
What you want is to get just 1 value emitted and then be done. Several options
What I do:
contentService.loaded .pipe( first(), ) .subscribe(...);
OR, just as good:
contentService.loaded .pipe( take(1), ) .subscribe(...);
use Promises, they are not deprecated and if you just need always exactly ONE value, then there is really no useCase for an "Observable" (or would you always use a number and make a string out of it when you need a string.. just because numbers are an amazing thing ;)
Take care!