es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

La suscripción a Http no funciona en el Servicio Angular.

Estoy trabajando en un proyecto y necesito recuperar datos de un servidor personalizado. Creé un servicio Httpclient para manejar solicitudes y me encontré con este problema: cuando intento realizar la suscripción para pasar datos al componente, no pasa nada, pero si hago la suscripción en el componente, todo funciona bien. Resumo el código a continuación:

El componente:

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();
  }
}

La línea comentada es la que funciona aquí, pero no en el servicio. La que no está comentada es lo que quiero que funcione correctamente.

El servicio:

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) {
        // error del lado del cliente
        errorMessage = `Error: ${error.error.message}`;
    } else {
        // error del lado del servidor
        errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;
    }
    console.log(errorMessage);
    return throwError(() => new Error(errorMessage))
  }
}

El @NgModule en app.module.ts:

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

Soy un poco nuevo en Angular, así que tal vez me esté perdiendo algo o no entendí bien cómo funciona realmente Observable.</food[]></food[]>

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    En el código proporcionado, el método getInHomeList() en ApiService devuelve una matriz que contiene el resultado y el error. Este método realiza una solicitud HTTP al servidor y se suscribe al observable para recuperar los datos. Sin embargo, ya que la solicitud HTTP es asíncrona, el resultado y el error no están disponibles inmediatamente después de la llamada al método. Por lo tanto, el resultado y el error devueltos serán indefinidos.

    Para solucionar este problema, el método getInHomeList() en ApiService debe devolver un Observable del array Food[]. El componente puede suscribirse a este observable y recuperar los datos. El siguiente fragmento de código muestra cómo modificar ApiService:

    import { Injectable } from '@angular/core';
    import { HttpClient } from '@angular/common/http';
    import { Food } from './api-models';
    import { catchError } from 'rxjs/operators';
    import { Observable, throwError } from 'rxjs';
    
    @Injectable({
      providedIn: 'root'
    })
    
    export class ApiService {
    
      constructor(private http: HttpClient) {}
    
      getInHomeList(): Observable<food[]> {
        return this.http.get<food[]>('https://localhost:5001/').pipe(
          catchError(this.handleError)
        );
      }
    
      private handleError(error: any) {
        let errorMessage = '';
        if (error.error instanceof ErrorEvent) {
            // error de lado del cliente
            errorMessage = `Error: ${error.error.message}`;
        } else {
            // error de lado del servidor
            errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;
        }
        console.log(errorMessage);
        return throwError(() => new Error(errorMessage));
      }
    
    }
    

    En el componente, el método ngOnInit() puede suscribirse al Observable getInHomeList() y recuperar los datos. El siguiente fragmento de código muestra cómo modificar InHomeListComponent:

    import { Component, OnInit } from '@angular/core';
    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) {}
    
      ngOnInit() {
        this.api.getInHomeList().subscribe(
          data => this.res = data,
          error => this.error = error
        );
      }
    }
    

    Al modificar el método getInHomeList() en ApiService para devolver un Observable y suscribirse a este Observable en el componente, se pueden recuperar los datos correctamente.</food[]></food[]>

Comments are closed.