简体   繁体   中英

Undefined variable when calling a service

I have a service that call two method of and webapi. Here's the implementation:

geo.service.ts

import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { environment } from 'src/environments/environment';
import { CountryResponse } from '../models/country.interface';
import { StateResponse } from '../models/state.interface';

@Injectable({
  providedIn: 'root',
})
export class GeoService {
  private apiUrl = environment.apiUrl + 'parameter';

  constructor(private http: HttpClient) {}

  getCountry(): Observable<CountryResponse> {
    let requestUrl = this.apiUrl + '/country';
    return this.http.get<CountryResponse>(requestUrl);
  }

  getStates(
    country_id: string): Observable<StateResponse[]> {
    let requestUrl = this.apiUrl + '/country/' + country_id + '/state';
    return this.http.get<StateResponse[]>(requestUrl);
  }

And my ngOnInit in component

            this.geo_service
              .getCountry()
              .subscribe(
                (data) => {
                  this.country = data; //works fine
                },
                (err) => {
                  this.notification_service.showError(
                    'Se ha producido un error'
                  );
                  console.log(err);
                }
              );

            this.geo_service
              .getState(
                this.country.country_id //undefined
              )
              .subscribe(
                (data) => {
                  this.state = data;
                },
                (err) => {
                  this.notification_service.showError(
                    'Se ha producido un error'
                  );
                  console.log(err);
                }
              );

the problem is: this.country is undefined on getState call method in ngOnInit and i don't know why, and how to fix it. But the data is ok, because this.country = data works fine as code says.

Angular 12.

Help please!

Calling an API in chain

The problem is simple, you have to synchronize the two async call. When you call the state the country is not ready yet. The simplest think you can do is:

 this.geo_service
              .getCountry()
              .subscribe(
                (data) => {
                  this.country = data
                   //here call the state one.
                    this.geo_service.getState(....
               }

You mentioned in a comment wanting to avoid nesting calls.

This can be done via RxJs streams.

const getCountryData$ = this.geo_service.getCountry().pipe(
  // tap is used for side effects mid stream
  tap(data => {
    this.country = data;
  })
)

Note for the following we're not directly relying on the side effect which in general we want to avoid.

const getStateData$ = getCountryData$.pipe(
  switchMap(countryData => {
    return this.geo_service.getState(countryData.country_id)
  })
).subscribe((data) => { this.state = data; })

Subscribe to getStateData$ triggers the stream.

In the code above I'm mixing imperative ( this.country = data ) and reactive coding. Personally I'd not use variables on the component but use the async pipe in the template to pull out the variables and this takes care of unsubscribing.

You can use catchError to handle error in a similar way to your question.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM