What is the best way to ensure that the second http call only runs after the first http call has completed, and passing an argument retrieved from the first call to the

My current challenge involves hitting one API to retrieve a specific string, storing it in a variable, and then passing it to another HTTP API call. However, I'm encountering an issue where the API call requiring the argument executes but never sends the correct request. (Just a beginner here by the way)

Below are the two API calls, with some personal information removed for privacy.

async getMatches() {
    return this.http.get('matchesUrl', {
      headers: {
        'Authorization': 'Bearer **'
      }
    })
  }

  async getMatchStats(matchId: string) {
    return this.http.get(`specificMatchUrl/${matchId}/`, {
      headers: {
        'Authorization': 'Bearer **'
      }
    })
  }

And here is my component:

import { Component, OnInit } from '@angular/core';
import {GetapiService} from '../getapi.service';

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

  title = '';
  wins = '';
  totalMatches = '';
  currentWinStreak = '';
  latestMap = '';
  matchId = '';
  constructor(
    private api: GetapiService
  ) { }

  async ngOnInit() {
    this.api.getPlayerStats().subscribe((data: any) => {
      this.title = data['game_id'];
      this.wins = data.lifetime['Wins']
      this.totalMatches = data.lifetime['Matches']
      this.currentWinStreak = data.lifetime['Current Win Streak']
    });

    (await this.api.getMatches()).subscribe((data: any) => {
      this.matchId = data.items[0].match_id;
    });

    (await this.api.getMatchStats(this.matchId)).subscribe((data: any) => {
      this.latestMap = data.rounds.round_stats['Map']
    })
  }

}

I initially believed that awaiting both calls would resolve this issue because getMatchStats won't be triggered until getMatches is completed and the matchId variable is assigned. However, upon making the call, the URL generated is incorrect and does not include the matchId. Despite console.log displaying the value correctly, there seems to be a misunderstanding on my end. I've checked similar questions but none seem to address my specific scenario... or at least as far as I comprehend. Thank you in advance for your assistance.

Answer №1

Avoid using async await, opt for switchMap rxjs operators

this.api.getMatches()).pipe(switchMap((data:any)=>{
   this.matchId =data.items[0].match_id;
   return this.api.getMatchStats(this.matchId)
})).subscribe((data: any) => {
      this.latestMap = data.rounds.round_stats['Map'];
});

Angular is brimming with Observables, utilizing rxjs operators allows us to transform / join /delay... observables. They require us to think in an "async way", which can be challenging but highly beneficial. Some of the key rxjs operators (though not limited to) include:

  1. forkJoin: joining multiple observables and waiting until all are completed
  2. switchMap: transforming one observable into another that depends on the first
  3. map: transforming the response of an Observable
  4. merge: creating an observable that emits a value each time one of several observables emit a value

I understand it may seem complex, but having a basic understanding of rxjs operators is essential for working with Angular

Answer №2

Start by making your initial call to this.api.getMatches() using the following structure:

myObservable.subscribe(
  x => console.log('Observer received a next value: ' + x),
  err => console.error('Observer encountered an error: ' + err),
  () => console.log('Observer received a complete notification')
);

After completing that, place your second call within the onComplete statement as shown below

() => {
    (this.api.getMatchStats(this.matchId)).subscribe((data: any) => {
      this.latestMap = data.rounds.round_stats['Map']
    })
}

Your code should appear like this afterwards

this.api.getMatches().subscribe(
  data => this.matchId = data.items[0].match_id;,
  err => console.error('Observer encountered an error: ' + err),
  () => {this.api.getMatchStats(this.matchId)).subscribe(
         data => {this.latestMap = data.rounds.round_stats['Map']}
        )}
);

That should do the trick. :)

Answer №3

Let's stick to the basics :)

Grabbing the match ID using: 
this.matchId = (await this.api.getMatches()).items[0].match_id;

Getting the latest map info with:
this.latestMap = (await 
  this.api.getMatchStats(this.matchId)).rounds.round_stats['Map'];

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

Working with objects in *ngFor in Ionic 2

I am utilizing Ionic 2 and attempting to display the content of a key-value array using an object. In order to display my collection, I am using a pipe in my HTML. Below is my HTML code: <ion-list> <ion-item *ngFor="let event of this.pdata. ...

Opt for ion-select with a range of i to j options

Looking to set up an ion-select menu in Ionic4 where users can pick a value between 20 and 220 without manually typing each number. I attempted to use the approach detailed in this post Tersest way to create an array of integers from 1..20 in JavaScript ...

Unable to run the command npm run env:restart

Currently, I am in the process of running a basic example. The initial setup involved configuring the convector workspace by installing convector-cli and hurley, as well as performing an npm installation. However, when attempting to execute npm run env:r ...

Memory Leak in Angular's Chain of mergeMap and concatMap Functions

I am facing an issue where a memory leak is being caused for each processed file during the upload of a 1 TB folder to Blob Storage. I have implemented a parallel processing pipeline using mergeMap to handle the files through a series of steps with concatM ...

What is the predefined value for a multi-select generated by the ng-for directive in Angular?

I am having trouble setting default selected values for the multi-select. Despite trying various methods such as initializing the ngModel to bind the variable and using [selected] = "selectedSegment == 'S1'", none of them seem to be effective fo ...

Stop the ion-fab-list from automatically closing when an element is selected within it

I'm having trouble getting a form to stay visible when a fab is clicked in my Ionic 4 app. Every time I click on a fab or another component within the ion-fab-list, the ion-fab-list automatically closes. How can I prevent this from happening and keep ...

The variable "theme" is referenced prior to being initialized

https://i.stack.imgur.com/QL0pa.png One of the variables in my code, theme, is set to be assigned a value from a for loop: let theme: Theme for (const themeObj of themeList) { const [muiThemeName, muiTheme] = Object.entries(themeObj)[0]!; if (muiThem ...

Generating dynamically loaded components in Angular 2 with lazy loading

We are integrating an angular2 app into a cms (Sitecore) where content editors need the ability to add, remove, and rearrange components on a page, as well as include new components as needed. This is achieved by having the cms generate script tags to loa ...

Angular - Modify the Background Color of a Table Row Upon Button Click

I am struggling to change the background color of only the selected row after clicking a button. Currently, my code changes the color of all rows. Here is a similar piece of code I have been working with: HTML <tr *ngFor="let data of (datas$ | asyn ...

Typescript counterpart of a collection of key-value pairs with string keys and string values

Within the API I'm currently working with, the response utilizes a data type of List<KeyValuePair<string, string>> in C#. The structure appears as shown below: "MetaData": [ { "key": "Name", &q ...

Ways to assign values to an array within an object

I'm attempting to transfer the contents of one array into an array within an object, but I keep encountering this error: Type 'any[]' is not assignable to type '[]'. Target allows only 0 element(s) but source may have more. Here ...

What is the reason that the css backdrop-filter: blur() is functioning properly everywhere except on the active bootstrap-4 list-group-item?

I have a gallery with an album-card component inside, and within that is a carousel. I noticed that when I add a list-group and set one of the items as active, it remains unblurred. Can anyone help me understand why? Here is the HTML for the gallery com ...

Angular Observable does not reflect updates automatically

I have a unique service that I utilize to pass on a particular value so that it is easily accessible to all components requiring it: setAnalysisStatus(statuses: AsyncAnalysis[]) { this.analysisStatus.next(statuses); } In ...

What is the best way to extract data from a text file that contains multiple data entries separated by pipes (|) using the fs module?

I'm currently utilizing the node.js fs module to read a text file. One thing that I'm wondering is, does the fs module only support reading text files or can it handle other file formats as well? Now, my primary inquiry is if the text file conta ...

Understanding how to retrieve the value count by comparing strings in JavaScript

In my array object, I am comparing each string and incrementing the value if one letter does not match. If three characters match with the string, then I increase the count value; otherwise, it remains 0. var obj = ["race", "sack", &qu ...

Building a custom user authentication system using Angular, Firebase, and Google authentication

Recently, I came across this video (in code), and implemented my Auth Service based on the example provided. However, my User Interface structure is slightly different: interface User { uid: string; email: string; photoURL: string; displayName: st ...

An issue has occurred: Cannot access the properties of an undefined object (specifically 'controls')

I encountered an error message stating "TypeError: Cannot read property 'controls' of undefined" in the code that I am not familiar with. My goal is to identify the source of this error. Below is the HTML code snippet from my webpage: <div ...

Issue: An object with keys {} is not suitable as a React child, causing an error

I am new to TypeScript and seeking help from the community. Currently, I am working on a to-do list project where I am using React and TypeScript together for the first time. However, I encountered an error that I cannot decipher. Any assistance would be g ...

Unable to iterate through elements when utilizing an external library: Incompatible types, 'Element[]' cannot be assigned to type 'string'

I've encountered an issue while trying to use the react-responsive carousel. It seems to work fine when I manually add my images, but when I try to add them through photos.map, it throws an error: Type 'Element[]' is not assignable to type ...

Color changes on mat-calendar when hovering

Is it possible to change the hover color of the Mat-calender element? I managed to do so using this CSS code: .mat-calendar-body-cell-content:hover { background-color:#something } The issue is that when hovering the cursor in the corner of the cell, the ...