Stopping the subscription to an observable within the component while adjusting parameters dynamically

FILTER SERVICE - implementation for basic data filtering using observables

import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { Filter } from '../../models/filter.model';
import { Convert } from '../../utils/converter';

@Injectable({
  providedIn: 'root'
})
export class FilterService {

  private currentFilter$ = new BehaviorSubject<{ page: number, limit: number }>({
    page: 0,
    limit: 20
  });

  constructor() { }

  private init(name: string) {
    let filterStr = localStorage.getItem(name);
    if (filterStr) {
      this.currentFilter$.next(Convert.fromJson<Filter>(filterStr))
    } else {
      localStorage.setItem(name, Convert.ToJson<Filter>(this.currentFilter$.value));
    }
  }

  private saveFilter(name: string, filter: Filter) {
    this.currentFilter$.next(filter);
    localStorage.setItem(name, Convert.ToJson<Filter>(filter));
  }

  public getFilter(name: string): Observable<Filter> {
    this.init(name);
    return this.currentFilter$;
  }

  public nextPage(name: string) {
    let filter = this.currentFilter$.value;
    filter.page = filter.page + 1;
    this.saveFilter(name, filter);
  }

  // Other methods omitted for brevity...

}

DOCUMENT ROUTE - dynamic parameter type: 302 = invoice, 306 = delivery note etc.

{ path: 'documents/:type', component: DocumentsComponent },

DOCUMENT COMPONENT

@Component({
  selector: 'app-documents',
  templateUrl: './documents.component.html',
  styleUrls: ['./documents.component.scss']
})
export class DocumentsComponent extends Unsubscriber implements OnInit {

  displayedColumns: string[] = ['number', 'customerName', 'date', 'paymentDate', 'settledStatus', 'net', 'vat', 'gross'];
  documentsDataSource: Document[] = [];
  sortColumn = '';
  sortDirection: SortDirection = '';
  searchText = '';
  title = '';
  filters?: FilterItem[] = [];
  type = 0;

  // Constructor and other code left unchanged...
});

UNSUBSCRIBER

import { Injectable, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';

@Injectable()
export abstract class Unsubscriber implements OnDestroy {

  subscription = new Subscription();

  constructor() { }

  ngOnDestroy(): void {
    console.log("Unsubscribing...");
    if (this.subscription) {
      this.subscription.unsubscribe();
    }
  }
}

RESULT - The issue arises with multiple subscriptions when changing routes in the document context. This can be resolved by properly unsubscribing to the previous subscriptions. When navigating between different components like Products or Customers before going back to Documents, everything functions correctly.

How can I address this problem?

https://i.stack.imgur.com/FrNF6.png

Answer №1

It seems like there are some patterns in your code that may be causing issues.

You are nesting Subscriptions inside other .subscribe() callbacks, which is not recommended. Instead, consider using RxJS operators like switchMap to chain them together.

this.subscription.add(this.route.params.pipe(
  switchMap((params) => {
    this.type = params["type"];
    this.title = this.getTitle(params["type"])

    return combineLatest([this.filterService.getFilter(`documents:${this.type}`), of(params])
  }),
  switchMap(([filter, params]) => {
    if (filter.orderBy) {
      this.sortColumn = filter.orderBy.split(" ")[0];
      this.sortDirection = filter.orderBy.split(" ")[1] === "asc" ? "asc" : "desc";
    }
    if (filter.search) {
      this.searchText = filter.search;
    }

    return this.documentsService.getDocuments(filter, params["type"])
  })
).subscribe(result => {
  this.documentsDataSource = result
}))

By restructuring your code, you can consolidate into just one Subscription that can be added to this.subscription.

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

Matching the appropriate data type for interface attributes

In the process of developing a module (module1), I have defined the following interface type: interface ModuleOneInterface { keyOne: customInterface; keyTwo: customInterface; keyThree: customInterface; } Now, as I work on another module (modul ...

Incompatibility Issues with TypeScript Function Overloading

In the process of setting up an NgRx store, I came across a pattern that I found myself using frequently: concatMap(action => of(action).pipe( withLatestFrom(this.store.pipe(select(fromBooks.getCollectionBookIds))) )), (found at the bottom ...

Encountering a problem with TypeScript while employing Promise.allSettled

My current code snippet: const neuroResponses = await Promise.allSettled(neuroRequests); const ret = neuroResponses.filter(response => response?.value?.data?.result[0]?.generated_text?.length > 0).map(({ value }) => value.data.result[0]?.genera ...

What could be causing the Angular router outlet to not route properly?

Check out this demo showcasing 2 outlets (Defined in app.module.ts): <router-outlet></router-outlet> <router-outlet name="b"></router-outlet> The specified routes are: const routes: Routes = [ { path: 'a', com ...

Error encountered when trying to access children components in Typescript, even though React.FC is being

I am facing an issue with a child component that has the following structure: interface ChildProps extends AnotherInterface{ route: string, exitAction: ActionCreatorWithoutPayload, } const ChildComponent:FC<ChildProps> = ({title, shape, rout ...

Switch from using getElementById to useRef in React components

There is a requirement to update a functional component that currently uses getElementById to instead utilize the useRef hook. The original code snippet is as follows: import React, { useState, useEffect, useRef } from 'react'; import { createPo ...

Transferring data between components in React by passing parameters through Links

When calling another component like <A x={y}/>, we can then access props.x inside component A. However, in the case of calling EditCertificate, the id needs to be passed to the component. I am using a Link here and struggling to pass the id successf ...

Testing units in Angular using different sets of test data

When it comes to unit testing a C# method with different sets of data, the Theory and InlineData attributes can be used to pass multiple inputs for testing purposes. [Theory] [InlineData("88X", "1234", "1234", "1234")] [InlineData("888", "123X", "1234", " ...

Using Two Unique Typeface Options in Material UI for ReactJS

Currently, in my React App, I am utilizing the Material UI library with Typescript instead of regular Javascript. I've encountered a small hurdle that I can't seem to overcome. The two typefaces I want to incorporate into my app are: Circular-S ...

Linking a string value to a specific data structure in TypeScript

I'm currently exploring typescript and I have a question about mapping a string value to a custom type when using templates in function calls. For instance: object.method<TypeMapper['CustomType']>([...]) In this scenario, 'Cust ...

The icon for caret down in FontAwesome is not displaying when using ngClass

I am experiencing an issue where only the fontawesome caret up is displayed when sorting a field, but the fontawesome caret down is not showing. I have provided the code snippet below. HTML <th (click)="sort('ref')">Ref {{reverse}} & ...

Issue with absolute import in React TypeScript application

An error occurs when trying to import a module, displaying the following message: Compiled with problems: × ERROR in ./src/App.tsx 5:0-33 Module not found: Error: Can't resolve 'routes' in 'F:\Tamrinat\Porfolio\microsite ...

I'm curious if someone can provide an explanation for `<->` in TypeScript

Just getting started with TypeScript. Can someone explain the meaning of this symbol <->? And, is ProductList actually a function in the code below? export const ProductList: React.FC<-> = ({ displayLoader, hasNextPage, notFound, on ...

When utilizing rxjs6 and recompose's componentFromStreamWithConfig, the error message "An incorrect object was supplied in place of a stream" is displayed

While working with rxjs 6.3.3 and recompose's componentFromStreamWithConfig function, I encountered an error message stating: You provided an invalid object where a stream was expected. You can provide an Observable, Promise, Array, or Iterable. To a ...

Automatic type inference for TypeScript getters

It appears that Typescript infers field types based solely on the private variable of a field, rather than taking into account the getter's return type union (1) or inferring from the getter itself (2): test('field type inference', () =& ...

Limiting only one checkbox to be selected in a dynamic FormArray in Angular requires some custom logic. This can

I am working on designing an Angular-12 dynamic FormArray: import { Component, OnInit, VERSION } from '@angular/core'; import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms'; @Component({ selecto ...

Executing a service prior to the loading of Angular 7 applications or components

Currently, I am in the process of developing an application using Angular 7. So far, everything is running smoothly as I have successfully managed API calls, JWT Token authentication with C#, and updating LocalStorage when needed during user login and logo ...

Challenges with deploying Angular applications and dealing with undefined properties within Angular code

Currently, I have successfully added new products to the database with all the desired properties. However, I am facing errors that are preventing me from deploying the application for production. Fixing these errors causes further issues where I cannot ad ...

I designed a dropdown menu with a searchable <mat-select> feature, where selecting an item is automatic when a space bar is pressed in the search box

Description : I have implemented a dropdown list using element that contains a list of items along with a search field. This allows users to easily search for specific items in the list instead of manually scrolling through a long dropdown menu. They can ...

Ways to delete a class in typescript

There's a menu on my website with li tags containing an a element for navigation. Everything is working fine, but I'm facing an issue where I need to remove all elements with the class seleccionado and only add it to the clicked li. I tried using ...