How to unsubscribe from a nested subscription in Angular 12 using rxjs

I have developed a basic authentication service and another component called Foo that performs the following tasks:

  • retrieve data from two lists
  • use the retrieved lists to subscribe to the authentication login observable and fetch additional data
export class AuthService implements OnInit {
  login: BehaviorSubject<Login | undefined> = new BehaviorSubject<Login | undefined>(undefined);
  public readonly login$: Observable<Login | undefined> = this.login.asObservable();

    constructor(private httpService: HttpHandlerService) { }

    ngOnInit(): void {
        this.httpService.login().subscribe(
            (login: Login) => {
                this.login.next(login);
            });
    }
}

export class Foo implements OnInit {
  subscription?: Subscription;
  listA?: KeyValuePair[];
  listB?: KeyValuePair[];

  constructor(private httpHandlerCached: HttpHandlerCachedService, private auth: AuthService) {
  }

  ngOnInit(): void {
    this.initLists().subscribe(([listA, listB]) => {
      this.listA = listA;
      this.listB = listB;

      this.initModule();
    });
  }

  initLists(): Observable<[KeyValuePair[], KeyValuePair[]]> {
    return forkJoin([
      this.httpHandlerCached.getAllListA(),
      this.httpHandlerCached.getAllListB()
    ]);
  }

  initModule(): void {
    this.auth.login$.subscribe((login) => {
      if (login) {
        this.httpHandler.getSomeData(login.id)
          .subscribe(someData => doSomeStuff(someData, listA, listB));
      }
    })
  }
}

In my version:

export class Foo implements OnInit, OnDestroy {
  listA?: KeyValuePair[];
  listB?: KeyValuePair[];
  subscription?: Subscription;

  constructor(private httpHandlerCached: HttpHandlerCachedService, private auth: AuthService) { }

  ngOnInit(): void {
    this.subscription = this.initLists().subscribe(([listA, listB]) => {
      this.listA = listA;
      this.listB = listB;

      this.initModule();
    });
  }

  initLists(): Observable<[KeyValuePair[], KeyValuePair[]]> {
    return forkJoin([
      this.httpHandlerCached.getAllListA(),
      this.httpHandlerCached.getAllListB()
    ]);
  }

  initModule(): void {
    this.subscription = this.auth.login$.subscribe((login) => {
      if (login) {
        this.httpHandler.getSomeData(login.id)
          .subscribe(someData => doSomeStuff(someData, listA, listB));
      }
    })
  }

  ngOnDestroy() {
    this.subscription?.unsubscribe();
  }
}

My inquiries:

  • Is this the correct approach for managing both subscriptions?
  • Do I need to unsubscribe in both scenarios?

Appreciate your input!

Answer №1

One of the main reasons we steer clear of nested subscriptions is because it can lead to messy cleanup processes. Instead, try incorporating some operators within the pipe, like this:

this.auth.login$.pipe(
    filter(Boolean),
    switchMap(({ id }) => this.httpHandler.getSomeData(id)),
).subscribe(someData => doSomeStuff(someData, listA, listB));

This approach reduces the need for multiple subscriptions. You can easily unsubscribe during component destruction, implement the takeUntil pattern (Angular RxJS Observable: takeUntil vs. unsubscribe with a Subscription), or even potentially eliminate explicit subscription by utilizing the `async` pipe in the template, depending on the functionality of `doSomeStuff`.

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

Ways to retrieve specific Observable elements?

Having a function like this: getCategories(): Observable<any> { return this.category.find({where: {clientId: this.userApi.getCurrentId()}}) }; The return type of this.category.find is Observable<T[]>. When I invoke g ...

custom form control component combined with an issue

Trying to develop a custom MatFormFieldControl with ControlValueAccessor implementation. Starting off with a familiar scenario: password form. The objective is to design a form field that takes a single string input, but contains its own internal form fo ...

I have a data.json file with a URL that I need to access in my view using Angular. How can I achieve this without relying on innerHTML?

Here is the JSON file data.json that I am referring to: { "id": 1, "title": "POC", "desc": "<a href='www.google.com'>HOMEPAGE</a>", "status": "done", "percentage_finished": 100 } I am tryi ...

Heroku deployment of Angular application encounters launching issue

Currently, I am facing a challenge with deploying my Angular App to Heroku using Git. The application works perfectly fine when run locally through the Angular CLI at localhost. To serve the static files, I have included a small Node.js server. Despite He ...

A guide on iterating through a JSON object fetched using Http in Angular 2/Typescript

I am attempting to extract specific data from my JSON file using http. The structure of the JSON is as follows: [{"name":"Name1","perc":33},{"name":"Name2","perc":22},{"name":"Name3","perc":41}] To loop through this retrieved object, I use the following ...

Issue with PrimeNG Carousel width on mobile devices

Currently, I am in the process of developing a system interface with Angular and PrimeNG specifically for mobile devices. The main requirement is to have a carousel to display a set of cards. After evaluating different options, I decided to utilize the ngP ...

angular component that takes a parameter with a function

Is there a way for my angular2 component to accept a function as a parameter? Uncaught Error: Template parse errors: Can't bind to 'click' since it isn't a known property of 'input'. (" minlength="{{minlength}}" [ERROR -&g ...

Mastering the art of managing unchecked and checked checkboxes in Angular 2: A comprehensive guide

I have a code snippet where I want to display the initial state of checkboxes based on the 'initialstatus' array in the UI. I should be able to randomly change the status of any checkbox on the UI, and that change should also be reflected in the ...

"Encountered an ENOENT error message following the deployment

I'm really hoping for some insight into the current situation. Deploying an Angular 7 / .Net Core 2 application to Azure is giving me trouble. I am utilizing the publish profile provided by Azure in Visual Studio. Everything runs smoothly when testi ...

Steps for initiating an Angular 4 project

While most developers have moved on to Angular 5, I was tasked with creating a project using Angular 4. After conducting research for several days, I discovered that downgrading the Angular CLI would allow me to accomplish this. By following this approach, ...

Exploring the power of spyOn within nested functions for AngularFirestore with Jasmine

Attempting to simulate AngularFirestore: beforeEach(() => { TestBed.configureTestingModule({ providers: [ { provide: AngularFirestore, useValue: { collection: () => ({ doc: () => ({ s ...

Enhancing view with Typescript progressions

My current view only displays a loader.gif and a message to the user. I am looking to enhance the user experience by adding a progress indicator, such as "Processing 1 of 50", during the data update process. The ts class interacts with a data service layer ...

Tips on how to verify if the Angular test with native elements has produced an error

Is there a way to detect errors in an Angular test that uses native elements? The test I am running is as follows: import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { MikeComponent } from './mike.component&a ...

Having trouble uploading images using Ionic/Angular to a PHP script

I've been working on incorporating image uploading functionality into my Ionic app. Despite reading multiple tutorials, I haven't been able to get it up and running successfully. I'm specifically aiming for the app to work smoothly in a web ...

The problem with MUI SwipeableDrawer not being recognized as a JSX.Element

Currently, I am implementing the SwipeableDrawer component in my project. However, an issue arises during the build process specifically related to the typings. I have made the effort to update both @types/react and @types/react-dom to version 18, but unf ...

what is the process for including multiple markers on Angular Google Maps?

Recently, I utilized the @agm/core module by running npm install @agm/core. This is the snippet of code that I implemented: <agm-map [latitude]="lat" [longitude]="lng"> <agm-marker *ngFor="let data of rooms" [latitude]="data.lat_long[0].lat" [ ...

Filling an Angular table with data from Google Sheets

I am looking to display data from Google Sheets in a table using Angular 6. I am utilizing the npm package get-sheet-done to create a JSONP and retrieve the data from Google Sheets as JSON. This allows me to update the data in my table dynamically when cha ...

What is the process for automatically initiating a service when importing a module in Angular?

I am curious about how I can automatically run a service within a module upon importing it, without the need for manual service injection and execution. This functionality is similar to how the RouterModule operates. @NgModule({ imports: [ Browser ...

Concealing forms within an Angular 5 application

I'm currently working on displaying the terms of use on the initial screen along with two buttons. If the user clicks the accept button, they will be directed to the authentication form. However, if they click refuse, the "Refused Terms" screen will a ...

Trigger a dispatched action within an NGRX selector

I want to ensure that the data in the store is both loaded and matches the router parameters. Since the router serves as the "source of truth," I plan on sending an action to fetch the data if it hasn't been loaded yet. Is it acceptable to perform the ...