Failure to Execute Angular HttpClient Request

I'm facing an issue with firing the HttpClient request. It seems like there might be a problem with importing or providing, but I can't pinpoint where it is exactly. The API works fine, but the call never goes through.

Here are the environment/versions details:

  • Angular: 15.1.2 Angular
  • CLI: 15.1.3
  • Node: 16.14.2
  • Package Manager: npm 8.5.0
  • OS: win32 x64

The structure is such that I have a main landing page with various widgets that offer a quick glimpse into the targeted content. Each widget has its own component. These components subscribe to Observables provided by services, which provide data for the widgets and are injected at the root.

app.module.ts

const pipes = [
  SignUpFormTextPipe,
  StageFormatTextPipe,
  StageTypeTextPipe,
  TeamSizeTextPipe,
  TournamentStatusTextPipe,
];

const providers = [HttpClientModule];

@NgModule({
  declarations: [...components, ...pipes],
  imports: [
    BrowserModule,
    FormsModule,
    ReactiveFormsModule,
    AppRoutingModule,
    HttpClientModule,
  ],
  providers: [...pipes, ...providers],
  bootstrap: [AppComponent],
})

The service

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Tournament } from '../models/tournament/tournament';
import { BehaviorSubject, Observable, take, tap } from 'rxjs';
import { TournamentsResponse } from '../models/api-responses/tournament/tournaments-response';

@Injectable({
  providedIn: 'root',
})
export class TournamentService {
  private baseUrl: 'http://localhost:5077/api/tournamens';

  initialTournaments: Tournament[] = [];
  private tournaments = new BehaviorSubject<Tournament[]>(
    this.initialTournaments
  );

  public tournaments$ = this.tournaments.asObservable();

  constructor(private httpClient: HttpClient) {}

  public getTournaments(): Observable<TournamentsResponse> {
    console.log('test 123'); // this works

    return this.httpClient.get<TournamentsResponse>(this.baseUrl).pipe(
      tap((resp) => {
        console.log(resp); // this doesn't work

        this.tournaments.next(resp.tournaments);

        return resp;
      }),
      take(1)
    );
  }
}

One of the components subscribing to it:

import { Component, OnInit } from '@angular/core';
import { Observable, Subject, takeUntil } from 'rxjs';
import { Tournament } from 'src/app/models/tournament/tournament';
import { NotificationService } from 'src/app/services/common/notification.service';
import { TournamentService } from 'src/app/services/tournament.service';

@Component({
  selector: 'app-upcoming-tourneys',
  templateUrl: './upcoming-tourneys.component.html',
  styleUrls: ['./upcoming-tourneys.component.css'],
})
export class UpcomingTourneysComponent implements OnInit {
  private destroy$: Subject<void> = new Subject<void>();

  upcomingTournaments$: Observable<Tournament[]> =
    this.tournamentService.tournaments$;

  constructor(
    private tournamentService: TournamentService,
    private notificationService: NotificationService
  ) {}

  ngOnInit() {
    console.log(this.tournamentService); // this gets fired and logged properly

    this.tournamentService
      .getTournaments()
      .pipe(takeUntil(this.destroy$))
      .subscribe({
        next: (resp) => {
          console.log(resp); // this doesn't fire
        },
        error: (resp) => {
          this.notificationService.showError(resp);
        },
      });
  }
}

and the related components HTML:

test if component is rendered
<div class="container-fluid" *ngIf="upcomingTournaments$ | async as upcomingTournaments">
  <div class="card">
    <div class="card-header" routerLink="/tournaments">
      Upcoming tournaments
    </div>
    <div class="card-body">
       <div *ngFor="let tourney of upcomingTournaments">
         ... content...
       </div>
    </div>
  </div>
</div>

This seems to be quite a puzzling error since I have the same setup working in another app. Some initial suggestions indicate that it could be an import error, but neither intelisense nor linter hints at it.

https://i.sstatic.net/AtEC4.png https://i.sstatic.net/QvBKR.png

*** UPDATE 1 *** I modified the service as per @flo's suggestion to use lastValueFrom(...). Unfortunately, the HTTP call still doesn't go through. :(

@Injectable({ providedIn: 'root' })
export class TournamentService {
  private baseUrl: 'http://localhost:5077/api/tournamens';

  initialTournaments: Tournament[] = [];
  private tournamentsSubject = new BehaviorSubject<Tournament[]>(
    this.initialTournaments
  );

  public tournaments$ = this.tournamentsSubject.asObservable();

  constructor(private httpClient: HttpClient) {}

  public getTournaments() {
    const result = lastValueFrom(
      this.httpClient.get<TournamentsResponse>(this.baseUrl)
    ).then((resp) => {
      this.tournamentsSubject.next(resp.tournaments);
    });
  }
}

In the component typescript file:

export class UpcomingTourneysComponent implements OnInit {
  upcomingTournaments$: Observable<Tournament[]> =
    this.tournamentService.tournaments$;

  constructor(private tournamentService: TournamentService) {}

  ngOnInit() {
    this.tournamentService.getTournaments();
  }
}

In the component template:

test if component is rendered
{{ upcomingTournaments$ | async }}
<div
  class="container-fluid"
  *ngIf="upcomingTournaments$ | async as upcomingTournaments"
>
....

*** UPDATE 2 *** As the previous attempts didn't work, I removed all observables and updated the service call. Still no luck with the API call being fired :*

The service:

  public getTournaments(): Observable<TournamentsResponse> {
    return this.httpClient.get<TournamentsResponse>(this.baseUrl);
  }

Component:

  ngOnInit() {
    const response = this.tournamentService.getTournaments().subscribe({
      next: (resp) => {
        console.log({ what: 'next call within service subscribe', resp }); // logs an ERROR TypeError: Cannot read properties of undefined (reading 'toLowerCase')
      },
    });
    console.log({ what: 'upcomingTourneysInit', response }); // here Response is SafeSubscriber
  }

Answer №1

You need to make sure you properly assign a value to your baseUrl in the service. The current code for the service is:

private baseUrl: 'http://localhost:5077/api/tournamens';

This is incorrect as it is not assigning the actual API url, but rather marking it as a type.

The correct way to declare this would be:

private baseUrl: string = 'http://localhost:5077/api/tournamens';

In addition, consider using Observables in your service and subscribing in your template with the async pipe to simplify handling subscriptions.

Answer №2

The issue lies within the tap function in your service. Make sure to refer to the documentation for clarification:

Tapping into the Observable The getHeros() method accesses the flow of observable values and displays a message, using the log() method, in the message area located at the bottom of the page.

The RxJS tap() operator facilitates this process by examining the observable values, performing actions on those values, and then passing them along. The tap() callback does not directly interact with the values themselves.

Keep in mind that Tap does not have direct access to the underlying data

Documentation Link

To fetch data from the http, you can utilize the function toPrimose (although it is deprecated - consider switching to lastValueFrom).

This is the recommended approach:

 public getTournaments(): Observable<TournamentsResponse> {
    console.log('test 123'); // this will execute
    const result = lastValueFrom(this.httpClient.get<TournamentsResponse>(this.baseUrl));

    this.tournaments.next(result.tournaments);      
);

Subsequently, make sure to subscribe to the tournaments$ in your application.

export class UpcomingTourneysComponent implements OnInit, OnDestroy {
  upcomingTournaments!: any;
  tournamentSub!: Subscription;

  constructor(private tournamentService: TournamentService) {}

  ngOnInit() {
    this.tournamentSub = this.tournamentService.tournaments$.subscribe(data => {
      upcomingTournaments = data;
    })
    this.tournamentService.getTournaments();
  }

  ngOnDestroy() {
    this.tournamentSub.unsubscribe()
  }
}

Following these steps will yield the desired outcome.

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

Guide on converting any object with keys of type string to a generic type

I'm grappling with a function that yields an Output generic type. In this function, I initiate an API request that responds with a json object. My aim is to have the function return this json object in the Output Generic type format Take a look at th ...

Testing Angular 7 components: A guide to validating input element values

Upon updating an operational application from Angular 4 to Angular 7, I encountered a discrepancy. Consider the HTML Input below: <input id="encryptedValue" readonly class="form-control" [ngModel]="Response.encryptedText" size="50" /> Prior to the ...

Identifying misspelled names in shared resources textures during PIXI.js loading

Our game utilizes TypeScript, Pixi.js, VSCode, and ESLint. We maintain a dictionary of image files as follows: export function getAllImages(): {name: string, extension: string}[] { return [ {name: 'tile_lumber', extension: '.svg ...

Setting the current date in Angular using TypeScript and storing it in a MySQL database

As I delve into learning Angular, I am focused on practicing with a form. Specifically, I am attempting to include the current date when inputting client records along with their RFC, branch, and cost. Unfortunately, my attempts have been unsuccessful in i ...

Trouble with Nested Routing in React Router Version 6: Route not Rendering

I'm facing issues nesting a path within another path in react-router-dom version 6. When I try to visit the nested argument's page (/blog/1), it shows up as a blank non-styled HTML page. However, when I add a child path to the root like /blog, it ...

How can I use TypeScript to copy data from the clipboard with a button click?

One of the functionalities I have implemented is copying data to the clipboard with a button press. However, I am now looking to achieve the same behavior for pasting data from the clipboard. Currently, the paste event only works when interacting with an i ...

Automatic type inference for functions in TypeScript with arguments

I am looking to define an interface with the following structure: interface CheckNActSetup<D, C> { defs: (event: Event) => D, context: (defs: D) => C; exec: (context: C) => any[]; when: ((context: C) => boolean)[]; } and implement it usi ...

Update the Angular material table with the set filtered results

Currently, I have a functioning Angular Material table with search capabilities. However, I am encountering an issue. The problem lies in the fact that when I navigate from 'route A' to 'route B' and pass a value to the search box in t ...

Display the data in ngx-charts heat map

I have been utilizing ngx charts to display data in a Heat Map. The implementation is smooth without encountering any issues. View Working Example | Heat Map However, I am interested in displaying the values of each grid rather than just on mouse hover. ...

Tips on saving a moved option item from one table to another in HTML:

Having an issue with dragging tables between different lists in Angular. The tables are generated by separate ngFor loops and I am using cdkDrag for the drag and drop functionality. The problem arises when I set an option in a dropdown and then drag the ta ...

Access network path through browser using Angular

I'm having trouble opening a network path from my browser using the code below. The browser keeps throwing an error saying it's unable to load local resources. Can you please provide some advice on this issue? public openUrl() { window.o ...

Utilizing Angular 2 with Bootstrap's popup modal feature

Is it possible to implement a popup modal in my Angular 2 application without relying on popular packages like ng2-opd-pop or similar solutions? I have included Bootstrap by importing it in my styles.css using '@import '../../../Content/bootstra ...

The compiler is showing an error with code TS5023, indicating that the option 'strictTemplates' is not recognized

When trying to compile my Angular application (v10), I encountered the following error message. An unexpected issue has occurred: tsconfig.json:14:5 - error TS5023: Unknown compiler option 'strictTemplates'. 14 "strictTemplates": t ...

A property in TypeScript with a type that depends on the value of an object

How can we troubleshoot the error not displaying in Typescript and resolve it effectively? Explore Typescript sandbox. enum Animal { BIRD = 'bird', DOG = 'dog', } interface Smth<T extends Animal = Animal> { id: number; a ...

Unique Version: Some effective tips for utilizing a fork of type definition such as @types

Currently, I am utilizing Typescript 2.0 along with @types and the experience has been quite positive. Thanks to @types, we can easily leverage type definitions by simply installing the package via npm. Surprisingly, I have not delved into how it actually ...

Tips for combining HttpClient's Observables with paramMap to create a dynamically loading component

I am currently working with an HTTPClient 'get' method that returns a JSON array of objects. I also utilize a key from the route params to extract a single object from that array. One interesting aspect of this component is its dynamic nature, w ...

Angular 16 HttpClient post request with asynchronous action

Here I am working on integrating JWT in Angular with a .Net Core API. When I start my Angular server and launch the application, I encounter the following scenarios: Attempting with correct credentials initially fails, but retrying allows it to work. Tryi ...

Ways to broaden the type signature of a Typescript comparator in order to facilitate sorting by properties nested within objects?

Here is a function that I created: arr.sort(alphabeticallyBy("name")) The function has the following signature: <T extends string>(prop: T) => (a: Partial<Record<T, string>>, b: Partial<Record<T, string>>) => ...

When the button onClick event is not functioning as expected in NextJS with TypeScript

After creating a login page with a button to sign in and hit an API, I encountered an issue where clicking the button does not trigger any action. I have checked the console log and no errors or responses are showing up. Could there be a mistake in my code ...

Tips for sending a String[] to my Angular 2 HTML template

In the export class of my component, I have a string array variable declared like this; barChartLabel:string[] = ['2006', '2007', '2008', '2009', '2010', '2011', '2012']; To display t ...