Executing several asynchronous functions in Angular 2

I am currently developing a mobile app and focusing on authentication. In order to display data to the user on my home page, I need to connect to various endpoints on an API that I have created.

Although all endpoints return the correct data when tested in Postman, I am encountering a null value in my second async call within the app.

I suspect that the issue lies in the sequencing of these calls, so I am seeking assistance on how to properly synchronize them for one to wait until the other finishes before proceeding.

public login() {

this.showLoading();

this.userService.getUserIdFromUserName(this.registerCredentials.username) // WORKS
  .subscribe(
    res => {
      console.log(res);
      localStorage.setItem("UserId", res.toString());
    },
    err => {
      console.log(err);
    });

this.userService.getEmployeeIdFromUserId(localStorage.getItem("UserId")) // THIS RETURNS NULL 
  .subscribe(
    res => {
      console.log(res);
      localStorage.setItem("EmployeeId", res.toString());
    },
    err => {
      console.log(err);
    });

this.authService.login(this.registerCredentials)
  .subscribe(

    data => {
      this.loading.dismissAll();
      console.log('User logged in successfully! ', data);
      this.nav.push(TabsPage);
      localStorage.setItem("Username", this.registerCredentials.username);
      localStorage.setItem("isLoggedIn", "true");
    },

    error => {
      this.loading.dismissAll();
      this.showAlert("Uh oh!", "Something went wrong. Please re-enter your login credentials or check your connection.");
      console.log(error);
    });
  }

Answer №1

Your current code is causing an error due to a bug present in it. The issue lies in the sequence of three calls within your code, labeled as A), B), and C):

A) this.userService.getUserIdFromUserName(this.registerCredentials.username) // WORKS

B) this.userService.getEmployeeIdFromUserId(localStorage.getItem("UserId")) // THIS RETURNS NULL 

C) this.authService.login(this.registerCredentials)

To understand RXJS better, you must grasp the concept of cold Observables (which contain all information necessary to initiate an async operation) versus hot Observables (where the async operation has already begun).

The actions A), B), and C) set up cold observables that only start running once you invoke .subscribe() on them. Given this, at the time B) is executed, A) is already underway but not yet finished. As a result, calling localStorage.getItem("UserId") will return null since A) has not triggered its subscriber's next callback.

In order for B) to wait for A), it is advisable to pass the result from A) to B) without relying on global state like localStorage. This can be achieved using the .mergeMap() operator:

this.userService.getUserIdFromUserName(this.registerCredentials.username) // WORKS
  .map(res => res.toString())
  .do(userId => localStorage.setItem("UserId", userId))
  .mergeMap(userId => this.userService.getEmployeeIdFromUserId(userId))
  .map(res => res.toString())
  .do(employeeId => localStorage.setItem("EmployeeId", employeeId))
  .subscribe(
    employeeId => {
      console.log(employeeId);      
    },
    err => {
      console.log(err);
    });

RXJS includes built-in error handling throughout the Observable chain. If executing C) concurrently is required, consider utilizing .forkJoin().

For a more practical understanding of .mergeMap(), refer to: SwitchMap vs MergeMap in the #ngrx example

Answer №2

Make sure to add this line for it to function properly: import 'rxjs/Rx'

this.userService.getUsernameFromId(this.registerCredentials.id)
  .map(res => res.toString())
  .do(username => {
      console.log(res);
      localStorage.setItem("Username", username);
    })
  .flatMap(username => {
       return this.userService.getUserIdFromUsername(username);
     })
  .do(res => {
      console.log(res);
      localStorage.setItem("UserId", res.toString());
    })

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

Enhancing the visual appeal of a standard jQuery slider with thumbnails

Recently, I incorporated the Basic jQuery slider into my website, which can be found at . As a novice in jQuery but well-versed in HTML and CSS, I have managed to make it work seamlessly on my site. However, I am curious to know if there is a way to displa ...

How can I eliminate the blinking cursor that appears after selecting an option from a dropdown using ng-select in Angular?

When using ng-select in Angular 5 for dropdowns, I have encountered an issue where the blinking cursor position does not behave as expected. After selecting an option from the dropdown, the cursor jumps to the start of the text instead of remaining at th ...

Tips for adding elements to an angular $scope.array?

Currently, I am facing an issue that I cannot seem to pinpoint (most likely due to my limited expertise in AngularJS). In my HTML file, I have a basic ng-repeat set up like this: <ul> <li ng-repeat="fot in fotografia"><img src="{{fot.path ...

Conceal the iframe if the source is http:// and there is no associated

Is there a way to hide the iframe only if the src starts with "http://"? This is what I have tried so far: <script type="text/javascript> if ( $('iframe[src^="http://"]') ) document.getElementById('iframe').style.d ...

Execute a grandchild function in Angular that triggers its grandparent function

I'm currently working with a component structure that looks like this: Component A -> Component B -> Component C Within the template of Component C, there is a button that triggers a function in the 'code behind' when clicked. My go ...

The error event in events.js on line 72 was not properly handled, causing an exception to be thrown

When attempting to utilize the node-ar-drone package to control an AR Parrot Drone 2 and interface with it, I encounter errors after connecting to the drone's wireless network on my OSX Yosemite: 587214779:examples mona$ node png-stream.js Connectin ...

Why are my class data types not aligning with JSON objects?

In my Node.js project using TypeScript, I have defined the Tariff and Tariffs classes. I also generated fake data in JSON format that should align with these Classes. However, I encountered an error in the resolve() method stating: Argument of type &apo ...

Tips for creating a sequelize transaction in TypeScript

I am currently working with sequelize, node js, and TypeScript. I am looking to convert the following command into TypeScript. return sequelize.transaction().then(function (t) { return User.create({ firstName: 'Homer', lastName: ' ...

Need to send emails to two separate users? Look no further than Resend.com for a quick and

I am currently utilizing resend.com to send an email containing different variables to two distinct users. import type { NextApiRequest, NextApiResponse } from "next"; import { EmailTemplate } from "../../components/emails/EmailTemplate" ...

Utilizing a dropdown selection to trigger an IF statement in a function

I have an HTML code snippet as shown below: The value "Test" is just for my reference to ensure that the code is functioning properly :) <script> var tfa78 = document.getElementById("tfa_78").selvalue; if( tfa78 == "karte" ) { document.getEl ...

Convert the date into a string format instead of a UTC string representation

I am currently working on a node.js project using TypeScript. In this project, I have a Slot class defined as follows: export class Slot { startTime: Date; constructor(_startTime: Date){ this.startTime = _startTime } } // Within a controller method ...

The functionality of Selection.modify is unfortunately limited when it comes to input and textarea elements in Firefox

Check out this demonstration (jsfiddle link): const input = document.querySelector('#input'); const textarea = document.querySelector('#textarea'); const div = document.querySelector('div'); const x = (e) => { if (e.ke ...

Having trouble with the ionic ion-nav-buttons not working on initial load?

My table view triggers the PixCtrl controller when a cell is clicked. If the connection is successful, data is retrieved using $http.get, otherwise sqlite is used. This setup works fine. However, I am facing an issue with my ion-nav-buttons being dynamic. ...

Tips for streamlining a conditional statement with three parameters

Looking to streamline this function with binary inputs: export const handleStepCompletion = (userSave: number, concur: number, signature: number) => { if (userSave === 0 && concur === 0 && signature === 0) { return {complet ...

What could be causing my Angular JS application to malfunction?

Presenting myFirstAngularApp.html <html ng-app="store"><!-- The "ng-app" attribute initializes an Angular app. Everything inside this tag is considered part of the Angular app due to ng-app --> <head> <link rel="stylesheet" type= ...

Implementing Azure AD authentication with Angular and .NET Core 2 Web API

My goal is to implement authentication in my application using Azure AD Currently, the flow of my application looks like this: User -> AngularApp -> Azure Login -> AngularApp with token -> API Call to backend with token -> Backend verifies ...

Error: Component with nested FormGroup does not have a valid value accessor for form control in Angular

In my setup, the parent component is utilizing a FormGroup and I am expecting the child components to notify any changes in value back to the parent. To achieve this, I am trying to implement NG_VALUE_ACCESSOR in the child component so that it can act like ...

What is the best way to ensure that the maximum price is mandatory when entering a minimum price?

Essentially, the process works like this: if a person inputs a minimum price but forgets to input a maximum price, then presses search, it will not perform the search and a message will appear next to the max price field reminding them to enter a maximum ...

Removing text that was added via the chart renderer in Highcharts can be accomplished by identifying the specific element

Instead of using a legend in my graph, I have added labels directly to the series (view example here). After drawing the graph with these labels attached, the user can click a button to add another series which hides some existing lines successfully. Howev ...

Customized Error Handling Function for Ajax Requests

I have a function that works perfectly, but I need to add six more buttons without repeating code. I want each callback to be customizable, with different text for each scenario (e.g. displaying "Please Log In" if the user is not an admin). How can I make ...