Unsubscribing from a nested observable - a step-by-step

In our Angular component, we leverage the ngOnDestroy() method to handle canceling http requests that are still pending when navigating away from a page. To avoid reloading data that has already been fetched, we utilize a custom generic cache helper on certain pages.

import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { AsyncSubject } from "rxjs";

@Injectable()
export class HttpCacheHelper {
    public cache = new Map<string, AsyncSubject<any>>();

    public constructor(private readonly http: HttpClient) {        

    }

    public get<T>(url: string): AsyncSubject<T> {
        if (!this.cache.has(url)) {
            const subject = new AsyncSubject<T>();
            this.cache.set(url, subject);
            this.http.get(url)
                .subscribe((data:any) => {
                    subject.next(data as T);
                    subject.complete();
                });
        }
        return this.cache.get(url);
    }
}

I'm facing an issue where unsubscribing from the AsyncSubject doesn't actually cancel my http call. How can I achieve proper cancellation in this scenario?

Answer №1

If you find yourself in this situation, there is no need to manually unsubscribe from the HTTP source (refer to this thread). In most cases, utilizing operators like take or flatMap can handle nested subscriptions efficiently.

Answer №2

Retrieve the subscription Object and cancel it.

import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { AsyncSubject, Subscription } from "rxjs";

@Injectable()
export class HttpCacheHelper {
    public cache = new Map<string, AsyncSubject<any>>();
    private mySubscription: Subscription;
    public constructor(private readonly http: HttpClient) {        

    }

    public fetch<T>(url: string): AsyncSubject<T> {
        if (!this.cache.has(url)) {
            const subject = new AsyncSubject<T>();
            this.cache.set(url, subject);
            this.mySubscription = this.http.get(url)
                .subscribe((data:any) => {
                    subject.next(data as T);
                    subject.complete();
                });
        }
        return this.cache.get(url);
    }

// Call this function when no longer needed
ngOnDestroy(): void {
    this.mySubscription.unsubscribe();
}

}

Answer №3

To stop receiving updates from the source, you will need to unsubscribe:

function fetchData<T>(url: string): Subject<T> {
    if (!this.cache.has(url)) {
        const subject = new Subject<T>();

        const subscription = this.http.get(url)
            .subscribe((data:any) => {
                subject.next(data as T);
                subject.complete();
            });

         this.cache.set(url, {
           subscribe(observer) { subject.subscribe(observer) },
           unsubscribe(observer) { subscription.unsubscribe() }
         });
    }

    return this.cache.get(url);
}

Answer №4

If you're looking to stop receiving emails, here's another way you can try

Start by deciding on a subject line for the unsubscribe request

private endSubscriptions$ = new Subject();

Insert this line of code before any .subscribe() that you want to cancel later

.pipe(takeUntil(this.endSubscriptions$))

For instance

this.anyService.getData()
  .pipe(takeUntil(this.endSubscriptions$))
  .subscribe((data: any) => {
    // Carry out necessary tasks...
  });

In your component, include ngOnDestroy() as follows

ngOnDestroy() {
  this.endSubscriptions$.next();
  this.endSubscriptions$.complete(); // Ensure complete unsubscription
}

As soon as ngOnDestroy() is called, all subscriptions utilizing takeUntil will be automatically unsubscribed

Answer №5

If I were to recommend an approach, I would suggest utilizing the combination of publishReplay and refCount:

@Injectable()
export class HttpCacheHelper {
  public cache = new Map<string, Observable<yourType>>();

  public constructor(private readonly http: HttpClient) {}

  public get<T>(url: string): Observable<T> {
    if (!this.cache.has(url)) {
      const obs = this.http.get(url).pipe(
         publishReplay(1),
         refCount()
      )

      this.cache.set(url, obs); 
    }

    return this.cache.get(url);
  }

  // Utilize the below function when necessary
  ngOnDestroy(): void {
    this.mySubscription.unsubscribe();
  }
}

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

Angular: Card disabled post-click

I am displaying three cards <div *ngFor="let catalog of catalogs;let i=index" (click)="goToProducts(catalog)"> <div> <div class="name-position text {{catalog.classe}}" style="font-size: 21px;"> ...

Tips for streamlining the use of http.get() with or without parameters

retrievePosts(userId?: string): Observable<any> { const params = userId ? new HttpParams().set('userId', userId.toString()) : null; return this.http.get(ApiUrl + ApiPath, { params }); } I am attempting to streamline the two http.get ca ...

What could be causing the errors I'm encountering in my TypeScript component within AngularJS?

I am working with an AngularJS component written in TypeScript called news.component.ts. This component makes a call to a service named google.service.ts in order to fetch news RSS using a service that converts XML to JSON. Within the NewsComponent, I hav ...

Error TS2309: TypeScript encountered an error in Types/node/index.d.ts

I recently upgraded my .Net Core Angular 2 project using SystemJs from Typings to @Types. The entire project has been rebuilt with the latest VS tooling for .Net Core 1.0.1, TypeScript 2.0.10, and Node.js 7.0.0 as of 12/21/2016. Everything was working fi ...

Step-by-step guide to linking a matTooltip with a disabled mat-tab

Is there a way to attach a matTooltip to a mat-icon in a disabled mat-tab? It seems that this feature is disabled when the mat-tab itself is disabled. Has anyone else encountered this issue? (I am unable to place the mat-tab within a div, of course) Than ...

React, redux, and redux observable are all essential tools for developing web applications. They

I am currently working on determining the type of a promise's resolve function. Here is a snippet of the code, or you can find it on GitHub: https://github.com/Electra-project/Electra-Desktop/blob/master/src/app/header/epics.ts export function getSt ...

The styles and scripts in Angular.json are not functioning properly

Attempting to integrate Bootstrap into my Angular project, but encountering issues with Scripts and Styles in angular.json After trying to copy the path from the folder, I keep getting errors! "styles": [ "C:\AngularProjects\project1\no ...

A foundational NodeJS program in TypeScript featuring a structured client-utility-definition setup with adherence to stringent coding guidelines

What is the best way to set up a basic TypeScript framework for starting a program with strict settings, based on the following program structure? An initial "client" code containing the actual program logic A separate "utility" module for defining funct ...

Transform the request in an Angular2 and jQuery Ajax POST call

I'm in the process of migrating my application from angularJS to angular2 and I've encountered a roadblock with an ajax POST call. return $.ajax({ url: "http://www.url.com", crossDomain: true, contentType: 'applicati ...

Tips for incorporating ngIf within a td element

My dilemma is with a table I have that displays data from a database. I need to be able to edit the data based on certain qualifications, so I want to include two buttons - one for deleting and one for editing. These buttons should only be enabled if the r ...

Developing a TypeScript library through modular class implementation

I have developed a Web API and now I want to streamline my code by creating a library that can be reused in any new project I create that interacts with this API. My goal is to organize my code efficiently, so I plan to have separate classes for each endp ...

Exploring the hidden gems of npm package.json: the keys

There are some keys in the package.json file of Angular 2/4's source code that remain undocumented: { "name": "@angular/platform-browser/animations", "typings": "../animations.d.ts", "main": "../bundles/platform-browser-animations.umd.js", "m ...

In React, the edit mode fails to display class attributes

When I attempted to combine both the creation and editing functionalities in one form, I encountered a problem. Specifically, I was able to retrieve the correct ID value when editing an element, but I struggled to access the attribute values. import { yup ...

Utilizing React to pass parent state to a child component becomes more complex when the parent state is derived from external classes and is subsequently modified. In this scenario,

I'm struggling to find the right way to articulate my issue in the title because it's quite specific to my current situation. Basically, I have two external classes structured like this: class Config { public level: number = 1; //this is a s ...

The Angular data table is encountering an issue as the dataStream.pipe function is not recognized

I'm currently working on setting up a table using Angular data table, but I've run into an issue related to the dataSource. I'm seeing an error message that says "dataStream.pipe is not a function", and I'm having trouble resolving it. ...

Aurelia CLI encounters difficulty importing chart.js when using TypeScript

Currently, I am utilizing typescript with aurelia/aurelia-cli. After npm installing chart.js, I proceeded to add it to my aurelia.json file like so: "dependencies": [ ... { "name": "chartjs", "path": "../node_modules/chart.js/d ...

Trouble with Styling React-Toastify in TypeScript: struggling to adjust z-index in Toast Container

Currently in the process of developing a React application utilizing TypeScript, I have incorporated the React-Toastify library to handle notifications. However, encountering some challenges with the styling of the ToastContainer component. Specifically, ...

Error: Trying to access property '2' of a null value

I’ve been working on a project using Next.js with TypeScript, focusing on encryption and decryption. Specifically, I’m utilizing the 'crypto' module of Node.js (@types/nodejs). However, I encountered an error while attempting to employ the &a ...

Using TypeScript and controllerAs with $rootScope

I am currently developing an application using Angular 1 and Typescript. Here is the code snippet for my Login Controller: module TheHub { /** * Controller for the login page. */ export class LoginController { static $inject = [ ...

Stop focusing on mat-select after a selection is made

I am encountering an issue with the following code in my .html file: <mat-form-field> <mat-select #selector(selectionChange)="onSelectionChange($event.value)"> <mat-option *ngFor="let test of tests" [value]="test"> </ma ...