Troubleshooting Service Angular's Http Subscription Issue

I am currently working on a project that involves retrieving data from a custom server. I have created an httpclient service to handle requests, but I am facing an issue. When I attempt to subscribe and pass data to the component, nothing happens. However, if I perform the subscription directly in the component, everything works as expected. Below is a summarized version of the code:

The component:

import { HttpClient } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { BehaviorSubject, catchError, map, Observable, of} from 'rxjs';
import { Food } from '../api/api-models';
import { ApiService } from '../api/api.service';

@Component({
  selector: 'app-in-home-list',
  templateUrl: './in-home-list.component.html',
  styleUrls: ['./in-home-list.component.css']
})
export class InHomeListComponent implements OnInit {

  res: Food[];
  error: string;

  constructor( private api: ApiService, private http: HttpClient){
  }

  ngOnInit() {
    //this.http.get<Food[]>('https://localhost:5001/').pipe(catchError(this.api.handleError)).subscribe({next: r => this.res = r, error: e => this.error = e});
    [this.res, this.error] = this.api.getInHomeList();
  }
}

The commented line works inside the component, but not in the service. The uncommented part is what I want to function correctly.

The service:

import { Injectable} from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Food } from './api-models';
import { catchError, throwError } from 'rxjs';

@Injectable({
  providedIn: 'root'
})

export class ApiService {

  private result: Food[];
  private error: string;

  constructor( private http: HttpClient) {

  }

  getInHomeList(): [Food[], string] {

    this.http.get<Food[]>('https://localhost:5001/').pipe(catchError(this.handleError)).subscribe({next: r => this.result = r, error: e => this.error = e});

    return [this.result, this.error];
  }

  handleError(error: any) {
    let errorMessage = "";
    if (error.error instanceof ErrorEvent) {
        // client-side error
        errorMessage = `Error: ${error.error.message}`;
    } else {
        // server-side error
        errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;
    }
    console.log(errorMessage);
    return throwError(() => new Error(errorMessage))
  }
}

The @NgModule in app.module.ts:

@NgModule({
  declarations: [
    AppComponent,
    InHomeListComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
  ],
  providers: [
    ApiService
  ],
  bootstrap: [AppComponent]
})

As a newcomer to Angular, I may be missing something or not fully understanding how Observables work.

Answer №1

The explanation provided above highlights the asynchronous nature of the content within the "subscribe" method. This implies that the execution of your getInHomeList() method may not follow the sequence in which it is written. Essentially, while the "subscribe()" method might take a few seconds to receive a response, the "return" statement will execute immediately without any data.

A common approach for handling http data-services involves returning the observable itself to the component:

public getInHomeList(): Observable<Food[]> {
    return this.http.get<Food[]>('https://localhost:5001/')
    .pipe(catchError(this.handleError));
}

handleError(error: any) {
    let errorMessage = "";
    if (error.error instanceof ErrorEvent) {
        // client-side error
        errorMessage = `Error: ${error.error.message}`;
    } else {
        // server-side error
        errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;
    }
    console.log(errorMessage);
    return throwError(() => new Error(errorMessage))
}

Subsequently, you can subscribe to the observable and retrieve the results in any component where they are required:

ngOnInit() {
    this.api.getInHomeList()
        .subscribe({next: r => this.res = r, error: e => this.error = e});
}

Given that the inside of the "subscribe" method operates asynchronously, there might be a delay in setting the value of "R". Nevertheless, regardless of the response time, the remaining part of the ngOnInit() method will continue its execution.

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

The labels for my Angular Material form within the dialogue are not visible and the styling appears incorrect until I begin inputting information

https://i.sstatic.net/njp4A.png Upon opening the dialogue, I noticed that only the phone number, email, name, and location fields were properly styled, while the others were not and the labels weren't displaying. Prior to adding appearence="out ...

The NGRX state in Angular is not being properly saved by the local storage

Currently, I am utilizing NGRX for state management within my Angular application. While NGRX is functioning correctly, I have encountered an issue with using local storage to persist the NGRX state. Upon refreshing the browser, the NGRX data reverts back ...

Angular element gives back an undefined value

Why does my second function getRatings() return undefined in console.log, even though the first API function is working fine and logging data without any issues? I have a service file with two functions that return API and array data. In the constructor ...

What causes a double fill when assigning to a single cell in a 2-dimensional array in Javascript?

I stumbled upon this code snippet featured in a challenging Leetcode problem: function digArtifacts(n: number, artifacts: number[][], dig: number[][]): number { const land: boolean[][] = new Array(n).fill(new Array(n).fill(false)) console.log ...

Troubleshooting Appium error management is ineffective

As a newcomer to appium, I might have made some mistakes. I'm encountering a problem with appium while using wdio and jasmine. it('wtf', (done) => { client.init().element('someName').getText() // ^ here ...

Can you explain the significance of <this> within TypeScript generics?

Our application employs express along with TypeScript. While exploring their type definitions, I stumbled upon the following snippet and I'm curious about its meaning: export interface IRouter extends RequestHandler { all: IRouterMatcher<this& ...

Is there a way to pre-load the content ahead of the footer?

My footer appears before the content is fully loaded. In my navbar, I have multiple buttons that open new components when clicked. When a user clicks on an event, it emits after the event data is loaded from the API and the footer loads correctly at that t ...

Dynamically setting the IMG SRC attribute with the base64 result of a FileReader for file input

Looking for a little guidance on something new, I'll keep it brief because I'm sure it's just some small detail I'm overlooking... Starting with an image like this, where currentImage is the initial existing image path; <img src="{ ...

Dealing with Cross-Origin Resource Sharing Problems in Angular 8 REST API

I am currently working with 2 components: The first component, "CurrenciesComponent," is being loaded. @Component({ selector: 'app-currencies', templateUrl: './currencies.component.html', styleUrls: ['./currencies.componen ...

The Capacitor Community Electron Platform, which combines IONIC, Angular, and Electron, encountered a TypeError: [ERR_INVALID_ARG_TYPE]. This error message indicates that the "path" argument must be in the

I have been attempting to follow the guidelines provided on to integrate the Capacitor Community Electron into a brand new Ionic Angular Test App. Everything is going smoothly until I reach the step where I need to add the platform as per the instructions ...

Closing a popover in NG-bootstrap from its container

I'm working on a container component named file-container, which includes an ngbPopover button. Inside the popover, there is another component used for selecting a file to upload. <button type="button" class="btn btn-secondary popover-btn ...

Unable to cancel the setTimeout function by using clearTimeout as the value appears to be null for unknown reasons

Within my react-native application, I am attempting to halt the execution of a setTimeout function by utilizing clearTimeout. The instance of setTimeout is stored in a global variable. let timeoutId: any = null; const doOtp = () => { if(can ...

Looking for a top-notch type definition management solution for Typescript, similar to tsd?

When considering the use of Typescript, the resolution of type definition files (*.d.ts) is essential. There are various systems for managing Typescript definition files, including: tsd typings @types It seems that tsd is the oldest system and the orig ...

Is it possible to invoke a function exclusively on the center item within an ngx-owl-carousel?

Is there a way to call a function only when an element is in the center of a slider? This is my HTML: <owl-carousel-o [options]="customOptions"> <ng-container *ngFor="let slide of slides"> <ng-template carous ...

Using Angular DI to inject a specific token value into a provider factory

Can an InjectionToken be injected into a factory provider? This is what I have implemented: export const HOST_TOKEN = new InjectionToken<string>("host"); let configDataServiceFactory = (userService: UserService, host: string) => { return ne ...

The Angular 2 bootstrap function is throwing an error stating that the argument type AppComponent cannot be assigned to the parameter type Type

Presenting my very first Angular 2 application with a simple Hello World example, inspired by the Angular 2 quick start guide. import {Component} from 'angular2/core'; import {bootstrap} from 'angular2/platform/browser'; @Component({ ...

Trouble encountered when using RxJS zip and pipe together

In my Angular Resolver, I am facing a scenario where I need to wait for two server calls. The catch is that the second server call is optional and can be skipped based on user input. This data retrieval process is crucial for loading the next page seamless ...

Using iframe to display local HTML content in React or Angular development

I'm having trouble displaying a local HTML file in an iframe. In both Angular and React, it works fine on development mode, but when deployed to production (AWS Amplify), I encounter the error message "cannot match any routes". I have tried all the s ...

Create data transfer objects in openApi using NestJS without the need for a Controller

In developing a NestJS service that serves as a REST API while also sending messages to NATS, we've successfully utilized the NestJS support for generating OpenAPI documentation and converting it into an SDK for our clients. However, we have encounter ...

Using Ionic to send email verification via Firebase

I have encountered an issue while attempting to send an email verification to users upon signing up. Even though the user is successfully added to Firebase, the email verification is not being sent out. Upon checking the console for errors, I found the f ...