2

I have a dialog that opens and contains a component... in the component I do a subscription. When closing I want to unsubscribe..

private deviceObserver: Observable<BreakpointState> = this.breakpointObserver.observe([Breakpoints.XSmall]);

this.deviceObserver.subscribe(result => {
  if (result.matches) {
    this.deviceType = 'mobile';
  } else {
    this.deviceType = 'desktop';
  }
});

ngOnDestroy() {
 this.deviceObserver.unsubscribe();
}

That gives me this error:

Property 'unsubscribe' does not exist on type 'Observable'. Did you mean 'subscribe'?

Mackelito
  • 4,213
  • 5
  • 39
  • 78
  • first you have to subscribe, assign it to a variable and then you can unsubscribe a subscription. – prady Jun 13 '18 at 11:37

2 Answers2

5

You can only use unsubscribe on a Subscription. You are trying to use it on a Observable.

If you use the observable inside your component using the async pipe, then you do not need to unsubscribe. This is automatically done by the framework.

If however you use it inside your component.ts, then one way is to do it like this. There are also other options, using the takeUntil pipe for instance:

private deviceObserver: Observable<BreakpointState> = 
                        this.breakpointObserver.observe([Breakpoints.XSmall]);

ngOnInit() {
  this.sub = this.deviceObserver.subscribe(result => {
    if (result.matches) {
      this.deviceType = 'mobile';
    } else {
      this.deviceType = 'desktop';
    }
  });
}

ngOnDestroy() {
 this.sub.unsubscribe();
}
Poul Kruijt
  • 69,713
  • 12
  • 145
  • 149
  • I had tried that but that broke features.. did some more digging and if I do this in the ngOnDestroy it breaks.. so I moved the unsubscribe to the closeDialog method and that worked fine! :) – Mackelito Jun 13 '18 at 11:39
  • that seems unlikely. Your code is using `unsubscribe` on an observable, you should not do that :) but safe a reference to the subscription (or use takeUntil) – Poul Kruijt Jun 13 '18 at 11:42
  • See my updated question (was missing code haha).. also posted the working code as an answer. I think there is something wrong when I open the cdk's OverlayRef and attaching the component to a ComponentPortal – Mackelito Jun 13 '18 at 11:46
  • The code in your answer uses the subscription reference, the code in your question does not. I see no reason why using the subscription reference wouldn't work in ngOnDestroy – Poul Kruijt Jun 13 '18 at 11:47
  • Well me neither but the document.addEventListener('keydown'... code works only on first keydown when I add the ngOnDestroy (with or without the subscribe/unsubscribe – Mackelito Jun 13 '18 at 12:49
  • why would you not use `(keydown)`? The reason it only works once, is probably because you are attaching it in some ngOnInit hook, and the element on which you attach it, gets destroyed and rebuild after every angular change detection check.. If it is inside an `*ngFor`, you should use the `trackBy` functionality – Poul Kruijt Jun 13 '18 at 13:22
  • not sure what you mean.. (this is not keydown in a component but in a service) – Mackelito Jun 13 '18 at 20:24
1

For some reason doing the unsubscribe in ngOnDestroy broke the app... This is how I solved it:

private deviceObserver: Observable<BreakpointState> = this.breakpointObserver.observe([Breakpoints.XSmall]);
private breakpointObserverSubscription: Subscription;


// in ngOnInit()
this.breakpointObserverSubscription = this.deviceObserver.subscribe(result => {
  if (result.matches) {
    this.deviceType = 'mobile';
  } else {
    this.deviceType = 'desktop';
  }
});

public closeSearch() {
 this.onClose.apply();
 this.breakpointObserverSubscription.unsubscribe();
}
Mackelito
  • 4,213
  • 5
  • 39
  • 78