Deciding whether to subscribe to an observable in the constructor or ngOnInit method in Angular

While I understand that this question has been asked numerous times on SO and other websites, I find myself getting confused by the varying answers.

2 INQUIRIES -

  1. Should I subscribe to my component in the constructor() or NgOnInit()?
  2. Is it necessary to use a pipe when subscribing to an Observable for Angular to handle the destruction, or can I avoid using ngOnDestroy? I'm puzzled by the presence of pipes after subscribing.

Let me illustrate how I am implementing one of my services; specifically, in my navbar component where I subscribe to changes in window size from a service.

In the constructor, I have implemented the following code:

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

Answer №1

  1. Utilizing the ngOnInit method for subscribing is a recommended practice because @Input bindings are not initialized until this lifecycle hook, making them unavailable in the constructor. Observable objects often rely on these values, so it's crucial to subscribe at the right time. Even if there are no dependencies, maintaining consistency by always placing subscriptions in the same location is a good habit.

  2. It's advisable to use the async pipe whenever possible to prevent manual subscription management. However, there are situations where manual subscription management is necessary or reasonable.

Answer №2

In my opinion, it is preferable to utilize the async pipe and allow angular to manage the unsubscribing process. This approach leads to cleaner code;

Let's examine a scenario where subscription happens 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()
  }
}

By incorporating an async pipe, we can refactor the code as follows:

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) {
  }
}

This revised code is not only more concise but also easier to test

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Using TypeScript syntax to define types; utilizing the export default keyword to incorporate an external JavaScript library within an Angular2

I've been attempting to incorporate a JavaScript library known as bricks.js into my project, but unfortunately, there isn't a publicly available type definition for it. The library seems to be exporting something along these lines: export defau ...

Unable to set up Typescript: The package v1.2.3 cannot meet the peerDependency requirements of its siblings

While attempting to set up Typescript for compiling my Angular2 app, I encountered an error message stating "The package [email protected] does not meet the peerDependencies requirements of its siblings." ...

Leveraging Expose in combination with class-transformer

I have a simple objective in mind: I need to convert the name of one property on my response DTO. refund-order.response.dto.ts export class RefundOrderResponseDto { @Expose({ name: 'order_reference' }) orderReference: string; } What I w ...

Challenges with Nested Reactive Form in Angular 4

I am utilizing Angular 4 reactive to develop nested forms. The structure of my forms is as follows: Form Group (userform) FormArray (users) FormGroup (idx) In the complete table, it falls under the Form Group. Each table row is a part of FormArray ...

Angular 2 Form Error: Control Not Found

I'm facing an issue with Angular 2 Forms where adding more than one control seems to be getting ignored. Despite following numerous guides on how to properly implement this, none of the suggested methods seem to work in my case. In my template, I hav ...

Using Angular 2 to Pass Parameters to a Custom Validator

Within my form builder, I have declared a validator like this: import { CustomValidators } from '../../custom-form-validators'; export class SelectTicketsComponent implements OnInit { maxNumber: number = 20; ...

The tap() function does not activate in an RXJS Pipe

There are two ways I can accomplish the same task, but I have a preference for the first method. However, it seems that the first approach is not working as expected (the tap() function is not being triggered). // Method A - does not work this.actions$. ...

Make sure to invoke the initialize function either in the ngOnInit lifecycle hook or

As a beginner in Angular 4, I have a question. What is the difference between calling a method like initializeMyObj() in the constructor versus ngOnInit in a TypeScript file? Thank you for your help! ...

Communication between parents and children is crucial for building strong relationships and providing validation

This question may have been asked in a complex manner before, but I will simplify it here. In my main component, I have a form tag and Submit Button. Within this component, there is a child component that contains an input field with a required attribute, ...

Instructions on how to post an array by its ID when the value changes in the form, correspond with the ID

Whenever I change the value in the radio button within a form popup, I want to trigger this action. Below is the corresponding HTML code: <ng-container cdkColumnDef="injected"> <mat-header-cell *cdkHeaderCellD ...

Issues with Plotly.js functionality arise following the update to Angular 13

Recently, I updated my Angular project from version 12 to version 13. One of the challenges I encountered is with Plotly while trying to create graphs. An error message pops up when launching the application: plotly.js:26321 Uncaught TypeError: Cannot rea ...

How can resolvers in GraphQL optimize data fetching based on necessity?

I am working with two unique GraphQL types: type Author { id: String! name: String! } type Book { id: String! author: Author! name: String! } Within my database structure, there exists a foreign key inside the books table: table authors (pseu ...

A guide on activating the <b-overlay> component when a child triggers an Axios request in vue.js

Is there a way to automatically activate the Bootstrap-vue overlay when any child element makes a request, such as using axios? I am looking for a solution that will trigger the overlay without manual intervention. <b-overlay> <child> ...

"Personalized labels for enhancing user insights on Microsoft Clarity

Is there a way to add a custom tag on MS Clarity specifically for tracking a user clicking the cancel button during a particular event? I am working on an Angular project and need guidance on how to achieve this. I attempted using script tags within the H ...

The ts-loader, antd, and typescript trio hits a stumbling block with the module index.less nowhere to

I am incorporating the antd React component library in my project and I'm using ts-loader to efficiently load the components. Currently, I am facing an issue while trying to configure webpack to transpile less files. The error I am encountering is as ...

Triggering a subsequent action in Ngrx depending on the data from the initial action

Currently, I am fetching a list of users using ngrx: this.users$ = this.store.select(fromReducer.getUsers); In my HTML template: <ul> <li *ngFor="let user of users$ | async"> {{user.id}} - {{user.name}} - {{user.email}} </ ...

Dealing with Angular routes in Express: Solving the issue of "res.sendFile is not a function"

I am facing an issue with my angular app running on a node server and serving static files. The app works perfectly fine when accessed from http://localhost:3000 and all angular routes function as expected. However, when I directly enter an address with an ...

Capture data from a Telegram bot and store it in a Google Sheet

I am trying to use a spreadsheet through a Telegram bot as a TODO list so that when I input something on my phone, it is saved in the spreadsheet. (I'm following this tutorial https://www.youtube.com/watch?v=XoTpdxbkGGk, which seems accurate with Goog ...

Restricting a checkbox to a maximum of 5 checkmarks

In a multi-column table, each column is represented by a checkmark. I want to limit the ability to tick a checkmark to only 5 checkmarks. Here is the code that has been implemented: <tbody> <ng-container *ngFor="let col of testData" ...

The class 'AngularFireList<{}>' cannot be assigned to the type 'FirebaseListObservable<any>'

Currently, I am developing a mobile app using Ionic 3, and I am facing an issue while trying to establish a connection with the Firebase database. The error message that keeps popping up is: Type 'AngularFireList<{}>' is not assignable to ...