0

I am trying to use observables, and I get an error saying "Cannot read property 'unsubscribe' of null". I am wondering where I should call my unsubscribe method. I am also wondering if my observable setup here is wrong. I have a service, a component, and a HTML template that looks something like this :

 // *** Service *** 
 private elements : Map<Category, string[]> = new Map<Category, string[]>();

 // I want to populate the map when the service is constructed
 constructor(private httpClient : HttpClient){
    for (enum in Category){
       if (!isNaN(enum as any)){
          this.httpClient.get<string[]>(someUrl + enum).subscibe(data => {
            this.elements.set(category, data);
          });
       }
    }
 }

 getElements(category: Category) : Observable<string[]> {
    return Observable.create(this.elements.get(category)); 
 }
 .
 .
 .
 // *** The component ***
 getCategoryList(category : Category) : Observable<string[]> {
   this.categoryService.getElements(category);
 }

 .
 .
 .
 // *** The template ****
 <div *ngFor="let element of getCategoryList('WARM_ELEMENTS') | async ">
    <div class="row">
       {{element}} 
    </div>
 </div>

I guess I need an unsubscribe method somewhere, or / and there is something wrong with my observable setup here (I'm learning Angular now).

TWok
  • 35
  • 1
  • 1
  • 5
  • 1
    Normally you unsubscribe from an Observable in your `ngOnDestroy` lifecycle hook. https://angular.io/api/core/OnDestroy – Z. Bagley Dec 17 '17 at 21:51
  • So I can unsubscribe in the ngOnDestroy hook in the component ? I don't understand how I can unsubscribe in this case ? – TWok Dec 17 '17 at 21:53
  • 1
    `.subscibe`? This code wouldn't even compile. Please post actual, compiling code, along with the exact and complete error you get. Bu why do you wrap an array of strings into an Observable? What's the point? Why not return the array of strings directly? And are you aware that Observable.create() axpects a function, not a array of strings? Again, that wouldn't compile. – JB Nizet Dec 17 '17 at 21:55

1 Answers1

0

Usually, you don't need to do unsubscribe when you use HttpClient if you want to make sure without a need to subscribe you can do take(1) instead.

 this.httpClient.get<string[]>(someUrl + enum).take(1).subscibe(data => {
    this.elements.set(category, data);
 });

if you want to really get subscription alive always (like when you use firebase), you need to unsubscribe inside OnDestory and assign that subscription to a variable so you can access it, but OnDestory is for components not for service actually it is for services too.

Anyway, there is alternatives; using takeWhile() and takeUntil().

You maybe need something like:

 private _keepAlive: boolean = true;

 constructor(private httpClient : HttpClient){
    for (enum in Category){
       if (!isNaN(enum as any)){
          this.httpClient.get<string[]>(someUrl + enum).takeWhile(() => this._keepAlive).subscibe(data => {
            this.elements.set(category, data);
          });
       }
    }
 }

 stopSubscription() : void { // this is just an option you can remove it
    this._keepAlive = false;
 }

 ngOnDestroy()
 {
    this._keepAlive = false;
 }

This is not really optimal, but I hope at least answer your question.

Here is another question and answers should be helpful for you: Angular/RxJs When should I unsubscribe from `Subscription`

Al-Mothafar
  • 7,949
  • 7
  • 68
  • 102
  • 1
    OnDestroy is also for services, not just components. – Ingo Bürk Dec 17 '17 at 22:04
  • 1
    And also your code would be leaking memory because you use a single subscription variable for the entire loop. The only reason it doesn't is because (as you said), HttpClient completes the observable. – Ingo Bürk Dec 17 '17 at 22:06
  • @IngoBürk thanks for info appreciated, and got no attention to loop :) I'll edit my answer. – Al-Mothafar Dec 17 '17 at 22:10