变量未定义,因为在API调用完成之前已实例化了它-Angular 7

时间:2019-01-12 21:20:41

标签: angular

我正在尝试创建天气应用。在需要接收为视图操作所需的数据之前,需要进行两个不同的api调用。

我创建了一个服务,该服务进行这些api调用并设置全局变量以供从不同组件访问。第一个调用是地理位置api。收到纬度和经度参数后,我可以再次调用天气api。

我遇到的问题是我的组件正在尝试在天气api调用完成之前访问全局变量,从而向我呈现未定义的变量。

我尝试使用async / await,但无法使其正常工作,最近才找到一个forkJoin rxjs方法。

当前,我所做的解决方案是使用setTimeout函数等待大约1秒钟,然后再进行下一行代码。我不认为这是执行此操作的最佳方法,但它确实有效。

有没有更好的方法可以研究并尝试?

main-component.ts

  currentlyForecast: string;

  lat: number;
  long: number;

  ngOnInit() {
    this.getGeo();
  }

  getGeo() {
    this.weather.getGeo()
      .subscribe((data: any) => {
        this.lat = data.latitude;
        this.long = data.longitude;
        this.getWeather(this.lat, this.long);
      });
  }

  getWeather(lat, long) {
    let location = { latitude: lat, longitude: long };

    this.weather.getWeather(location);
    setTimeout(() => {
      this.currentlyForecast = this.weather.currentlyForecast;
      console.log(this.currentlyForecast);
    }, 700);
  }

weather.service.ts

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';

const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type':  'application/json'
  })
};

@Injectable({
  providedIn: 'root'
})
export class WeatherService {

  // Weather parameters
  public currentlyForecast: any;
  public dailyForecast: any;
  public hourlyForecast: any;
  public minutelyForecast: any;

  private weatherUrl = 'http://localhost:3000/weather/data';
  private geoLocationUrl = 'http://localhost:3000/weather/geo';

  constructor(private http: HttpClient) {
  }

  getGeo() {
    return this.http.get(this.geoLocationUrl);
  }

  getWeather(location) {
    return this.http.post(this.weatherUrl, location, httpOptions)
      .subscribe((data: any) => {
        console.log(data)
        this.currentlyForecast = data.currently;
        this.dailyForecast = data.daily;
        this.hourlyForecast = data.hourly;
        this.minutelyForecast = data.minutely;
      });
  }

}

3 个答案:

答案 0 :(得分:1)

请执行以下更改代码。 :

// modify your service like below :  

 getWeather(location) {
    return this.http.post(this.weatherUrl, location, httpOptions)
      .map((data: any) => {
        console.log(data)
        // you can keep  these variables if needed here or
        // move them to component file
        this.currentlyForecast = data.currently;
        this.dailyForecast = data.daily;
        this.hourlyForecast = data.hourly;
        this.minutelyForecast = data.minutely;
        
        return  this.currentlyForecast; // returning this because you have used in componenet file
      });
  }
  
  // Now in component modify your method like below : 
  
  getWeather(lat, long) {
    let location = { latitude: lat, longitude: long };

    this.weather.getWeather(location).subscribe((result:any)=>{
       //result will contain currentlyForecast value
      this.currentlyForecast = result;
      console.log(this.currentlyForecast);
    });
  }
  
  

答案 1 :(得分:0)

我建议进行以下更改:

此方法返回承诺,Promise具有thencatch回调。

getWeather(location): Promise<any> { return this.http.post(this.weatherUrl, location, httpOptions).ToPromise(); }

在您的weather.service.ts中添加此方法:

public setData(data: any): void {
    this.currentlyForecast = data.currently;
    this.dailyForecast = data.daily;
    this.hourlyForecast = data.hourly;
    this.minutelyForecast = data.minutely;
}

在您的main-component.ts

 getWeather(lat, long) {
    let location = { latitude: lat, longitude: long };

    this.weather.getWeather(location)
      .then((data) => {
        this.weather.setData(data);
        this.currentlyForecast = this.weather.currentlyForecast;
        console.log(this.currentlyForecast);
      }).catch((error) => {
        console.error(error);
      });
  }

我们可以在以下位置看到它的工作:

https://stackblitz.com/edit/angular-xodqxj?embed=1&file=src/app/weather.service.ts

答案 2 :(得分:0)

  getWeather(location) {
    return this.http.post(this.weatherUrl, location, httpOptions)
      .pipe(
        map((data: any) => {
          console.log(data)
          this.currentlyForecast = data.currently;
          this.dailyForecast = data.daily;
          this.hourlyForecast = data.hourly;
          this.minutelyForecast = data.minutely;
          console.log(this.currentlyForecast);
          return this.currentlyForecast;
        })
      );
  }