Where to subscribe to an observable, constructor or ngoninit in Angular

14.3k views Asked by At

I know this is posted all over SO and the internet but I'm reading so many different things, I'm just a little confused now.

2 QUESTIONS -

  1. Where is the best place to subscribe to my component, the constructor(), or in NgOnInit()?
  2. Should I use a pipe when subscribing to an Observable so that Angular can destroy it or so I don't have to use ngondestroy? A little confused as to why there are pipes after subscribing?

Here is an example of one of my services where, in my navbar component, I subscribe to listening to a window size change coming from a service.

In my constructor, I have this -

this.responsiveService.getMobileStatus()
  .subscribe(mobileStatus => {
    this.isMobile = mobileStatus.status;
    if (mobileStatus.width < 568) {
      this.inputPlaceholder = this.placeholderWithSearch;
    } else {
      this.inputPlaceholder = this.placeholderWithoutSearch;
    }
  });

2

There are 2 answers

10
Owen Kelvin On

I would say better to use an async pipe and let angular handle the unsubscribing. It produces cleaner code;

lets consider the code where the subscribing is in the constructor

export class MyClassComponent implements OnInit, OnDestroy {
  sub: any;
  componentName: any;
  constructor(private navbarService: NavbarService) {
  }
  ngOnInit() {
    this.sub = this.navbarService.getComponentNameObv()
    .subscribe(componentName => {
      this.componentName = componentName;
    });
  }
  ngOnDestroy() {
    this.sub.unsubscribe()
  }
}

With an async pipe we can refactor

export class MyClassComponent {
  componentName$ = this.navbarService.getComponentNameObv();
  mobileStatus$ = this.responsiveService.getMobileStatus().pipe(
    tap(mobileStatus => {
      this.isMobile = mobileStatus.status;
      if (mobileStatus.width < 568) {
        this.inputPlaceholder = this.placeholderWithSearch;
      } else {
        this.inputPlaceholder = this.placeholderWithoutSearch;
      }
    })
  )
  constructor(private navbarService: NavbarService) {
  }
}

The code is much shorter and also easier to test

3
bryan60 On
  1. it's good practice to use ngOnInit to subscribe because @Input bindings are not initialized till this lifecycle hook, so they're not ready in the constructor, and often observables can depend upon these values. Even if they don't, it's just a good practice thing to keep it consistent, and always in the same place.

  2. you should use the async pipe whenever practical to avoid manual subscription management, but this is not always possible or reasonable.