RxJs operators prevent the need for multiple subscriptions through the use of looping mechanisms

Currently working on developing a navigation component for an Angular application. The code snippet below shows my current progress. I am looking to avoid the common issue of having multiple subscriptions within each other, known as the multiple subscription anti-pattern. Having trouble with the RxJs syntax and figuring out whether to use forkJoin, mergeMap, etc.

How can I refactor this code to eliminate the need for nested subscriptions?

This is what I currently have, which functions but contains a subscribe within a subscribe:

@Component({
  selector: 'ehrcc-nav',
  templateUrl: './nav.component.html',
  styleUrls: ['./nav.component.css']
})
export class NavComponent implements OnInit {

  applicationName: string = 'AppName';
  userDisplayName: string = '';
  isAuthorizedUser: boolean = false;
  isAdminUser: boolean = false;

  groupsList: MemberGroup[] = [];

  constructor(private userService: UserService,
    private auditService: UserAuditService,
    private router: Router) { }

  ngOnInit() {

    this.getDisplayName();

    this.userService.getGroupMembershipsForUser().subscribe(members => {
      this.groupsList = members;
      for (let g of this.groupsList){
        if (g.id === this.userService.usersGroupId){
          this.isAuthorizedUser = true;
          this.router.navigate(['/workItem']);
        }
        if (g.id === this.userService.adminGroupId){
          this.isAdminUser = true;
        }
      }
      this.logUserInfo();   <---- ANTI-PATTERN
     });

  }

  getDisplayName(){
    this.userService.getSignedInAzureADUser().subscribe(
      (user) => this.userDisplayName = user.displayName,
      (error: any) => {
        return console.log(' Error: ' + JSON.stringify(<any>error));
    });
  }

  logUserInfo(){
    var audit = new UserAudit();
    audit.Application = this.applicationName;
    audit.Environment = "UI";
    audit.EventType= "Authorization";
    audit.UserId = this.userDisplayName;
    audit.Details = ` User Is Authorized: ${this.isAuthorizedUser}, User Is Admin: ${this.isAdminUser}`;

    this.auditService.logUserInfo(audit)
    .subscribe({ 
      next: (id)=> console.log('Id created: '+ id),
      error: (error: any) => console.log(' Error: ' + JSON.stringify(<any>error) )
    });
  }
}

Answer №1

My journey to uncovering the cause of repetitive execution of certain subscribe code blocks led me to this very question.

Upon investigation, I discovered that the issue stemmed from services returning incomplete Observables, resulting in multiple executions. To remedy this, I implemented the use of auditTime, a function that:

Temporarily pauses processing for duration milliseconds before emitting the most recent value from the source Observable.

By integrating this solution into the existing code, a pipe with the auditTime operator can be added:

import { auditTime, ... } from 'rxjs/operators';

this.userService.getGroupMembershipsForUser().
 .pipe(auditTime(1E3)) // introduces a 1-second delay and fetches the latest data
 .subscribe(members => { ... });

Answer №2

To utilize forkJoin, refer to this link: https://www.learnrxjs.io/operators/combination/forkjoin.html

forkJoin({
   displayName: this.userService.getSignedInAzureADUser(), // Obtain observable subscription value
   groupMemberShip: this.userService.getGroupMembershipsForUser() 
})

Upon subscribing to forkJoin, an object containing all values will be returned. You can then invoke logUserInfo from it. Note that all observables must complete in order for forkJoin to emit.

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

Guidance on extracting values from an array based on the latest month in Angular

I have a list of data: var dataList = [{ "date": "2022-09-08T04:00:00.000Z", "value": "1.70", }, { "date": "2022-08-24T04:00:00.000Z", "value": "1.20", }, { "date": "2022-08-02T04:00:00.000Z", "value": "0.03", }, { ...

The QueryParams/ParamMap consistently returns as blank

Seeking assistance with retrieving a parameter called serverId from the URL. I have the following code setup: constructor(private peopleService: PeopleService, private route: ActivatedRoute) { this.route.paramMap.subscribe(params => { ...

The 'subscribe' property is not found in the type 'OperatorFunction<Response, Recipe[]>'

I'm encountering an issue while attempting to retrieve data from firebase "Property 'subscribe' does not exist on type 'OperatorFunction'" Any suggestions on what might be missing here? import { Injectable } from '@angula ...

Create a prop type that can be either a single number or an array of numbers, depending on the value of another

Seeking a solution, I am exploring an example using arrays with the 'multi' property. When 'multi' is true, the items should be of type number[]. Otherwise, they should be of type number. interface EnhancedSelectProps { items: multi ? ...

What steps can be taken to resolve the issue of 'modal bootstrap not being defined?

Looking to implement a modal for popups, but encountering an issue with the ng ///appmodule/appcomponent host.ngfactory.js on this page (which currently appears empty). user.html <div> <button data-toggle="modal" mat-raised-button="primary" ...

Improving Efficiency in Angular 2 for Managing a High Volume of Items

Imagine a scenario where I have created a component that showcases a list of items. export class ListComponent implements OnInit{ public list:any; constructor(private _ls: ListService) {} ngOnInit() { this._ls.listLoad().subscribe((data ...

Tips for updating a session cookie in nestjs

After successfully setting up session authentication using NestJS, I have always relied on JWT and set a short expiration time for access tokens. In order to obtain a new access token, the frontend must refresh it. Now, I am facing the challenge of implem ...

There is an issue with types in React when using TypeScript: The type '(user: User) => Element' cannot be assigned to the type '((props: User) => any) & ReactNode'

I'm encountering an error in the terminal and need some assistance. I am not well-versed in TypeScript, so any guidance to resolve this issue would be highly appreciated. https://i.stack.imgur.com/PWATV.png The Loadable component code: import { Circ ...

Utilizing the subclass type as a parameter in inheritance

Looking for a way to restrict a function in C# to only accept classes of a specific base class type? In my current implementation, I have a base class (which can also be an interface) and n-classes that extend it. Here is what I am currently doing: abstr ...

What is the best way to remove the underline from Angular Material input fields?

I am currently working with an input element in Angular Material: <md-input-container> <input type="text" mdInput placeholder=""> </md-input-container> While the input is focused, it displays an underline. Is there a way to hide or remo ...

Activate the spring profile for Angular2 development in order to enhance functionality

Our Web App utilizes Angular and Spring Boot technologies. We have implemented dev, test, and prod spring profiles to load varying properties based on the environment in which the application is running. This approach allows us to parametrize properties wi ...

To trigger a Bootstrap 5 modal in a child component from a button click in the parent component in Angular without the need to install ng-bootstrap is possible with the following approach

To achieve the functionality of opening a modal in a child component upon clicking a button in the parent component without using ngx-bootstrap due to restrictions, one approach is to add data-bs-target and data-bs-toggle attributes to the button. Addition ...

Tips for transferring information within a Material 2 dialog in Angular 2 from one component to another

While working with a Material 2 dialog, I have managed to retrieve data upon dialog close successfully. However, I am facing difficulties in finding a solution to pass data to the dialog using @Input. import {Component} from '@angular/core'; im ...

``Implementing a method to save the output of an asynchronous request in a global variable for future manipulation

It's been a week and I still can't figure this out. Being new to front-end development, I'm struggling with storing the response from subscribe in a global variable for future use. ngOnInit(): void { this.http.get<APIResponse>('ur ...

My eslint quote rules seem to be disregarded by Visual Studio Code

I am facing an issue with Visual Studio Code not following my eslint rules for my typescript project, particularly with quoting. More information about the configurations of my project can be found here: Typescript: Why doesn't Visual Studio Code repo ...

You must incorporate the formControlName within a parent formGroup directive to proceed. Ensure to include a formGroup in order to resolve this error

As a beginner in angular 8, I am currently facing the challenge of migrating an old project from angular JS to angular. Everything was going smoothly until I encountered the infamous error stating that formControlName must be used with a parent formGroup d ...

Typescript's conditional types define unique object fields based on specified conditions

I am looking to create a function (which will eventually be used as a React function component) in Typescript that receives a props object containing a list of lists of objects of any type. The goal is for the function to output a "key" for each object - i ...

What is the reason for injecting a service into 2 modules following the Singleton Pattern?

Here is the current file situation: AppService AppModule AModule AComponent BModule BComponent Regarding the Service, I have noticed that Angular will create two separate instances of the service if it is injected into two compone ...

Determine the data type of a parameter by referencing a prior parameter

Consider a scenario in my software where I have two distinct implementations of an Event Emitter. For instance: type HandlerA = (data: boolean) => void; type HandlerB = (data: number) => void; // HandlerB is somehow different from HandlerA type Eve ...

Comparing the Use of HttpHeaders Set versus Append in Angular

My caching interceptor is designed to check for the presence of an x-refresh header in incoming requests. If this header is found, it bypasses any cached request/response pairs associated with that specific endpoint and instead queries the server directly. ...