Where to subscribe to an observable, constructor or ngoninit in Angular [closed]
Asked Answered
F

2

19

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;
    }
  });
Facetious answered 10/10, 2020 at 19:38 Comment(0)
O
24
  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.

Overcurious answered 10/10, 2020 at 19:59 Comment(3)
thanks! good to know.Facetious
Can you explain when I should and shouldn't use the async pipe?Facetious
Like I said, whenever it is practical. If you’re just trying to use a value in template, then you should probably use the async pipe. But if you need that value other non template places or need to produce other effects based on the value, then the async pipe probably isn’t practical.Overcurious
C
5

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

China answered 10/10, 2020 at 19:55 Comment(10)
what if I have to do a bit of logic after I receive it? Instead of just setting 1 value like my example, I have to set a couple of values and do a little logic. Should it be in the constructor then or ngoninit?Facetious
You then would pipe the observable and depending on your desired result, you can use rxjs operators to transform the data or use the data for a particular purpose, any specific scenario?China
ya let me edit my OP to show the bit of logic.Facetious
ok I've edited my OP with a different example showing a bit of logic that gets run when I subscribe to service listening to a window resize event.Facetious
I have added a tap operator to tap into the observable streamChina
what benefit does pipe and then tap provide me. I know I don't have to use them. Maybe you can just explain it a little bit for me to understand the benefits of using both of them. Much appreciated! And what benefit do I have of not putting them in the constructor or ngoninit?Facetious
not sure what's going on, but using this example you provided me with pipe and tap, above the constructor, now doesn't catch the event like it should. But it does work in ngoninit and the constructorFacetious
It can only work if you set set the async pipe. In your html ensure you include mobileStatus$ | async for this approach to work.China
Just curious. If I want to access mobileStatus$ somewhere in the ts file below, how would I acccess a value from it? I know how to do it in html with the (mobileStatus$ | async).someprop but what about the typescript way?Facetious
Let us continue this discussion in chat.China

© 2022 - 2024 — McMap. All rights reserved.