0

Im trying to display this information about weather cities, but im having trouble at the last moment, I think. The API is OpenWeatherMap and the call is based on the docs. I've checked this post, tried to follow its logic but my problem remains, data wont render, with the error "ERROR Error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays."

This is my service:

export class WeatherService {

constructor(private http: HttpClient) { }

forecast: RootObject;

getForecast() {
  const url = 'http://api.openweathermap.org/data/2.5/forecast?lat=35&lon=139&APPID=ef48ddb3926ce0283de7291a09fd253e';
  return <Observable<RootObject[]>> this.http.get(url)
  .pipe(
      retry(3),
      catchError(this.handleError));
}

This is the generated interface:

export interface RootObject {
  coord: Coord;
  sys: Sys;
  weather: Weather[];
  main: Main;
  wind: Wind;
  rain: Rain;
  clouds: Clouds;
  dt: number;
  id: number;
  name: string;
  cod: number;
}

interface Clouds {
  all: number;
}

interface Rain {
  '3h': number;
}

interface Wind {
  speed: number;
  deg: number;
}

interface Main {
  temp: number;
  humidity: number;
  pressure: number;
  temp_min: number;
  temp_max: number;
}

interface Weather {
  id: number;
  main: string;
  description: string;
  icon: string;
}

interface Sys {
  country: string;
  sunrise: number;
  sunset: number;
}

interface Coord {
  lon: number;
  lat: number;
}

The component:

export class MainComponent implements OnInit {

foreCast: RootObject[];

  constructor(private weatherService: WeatherService) {
    this.getForecast();
   }

  ngOnInit() {
  }

getForecast() {
  this.weatherService.getForecast()
  .subscribe(data => {
    this.foreCast = data;
    console.log(this.foreCast);
  });
}

And the HTML:

<ul *ngFor="let wind of foreCast">


<li>{{wind.speed}}</li>

</ul>

This the log I get:

enter image description here

All the imports are in place, and the console.log show's me the retrieved object. What am I missing in this mapping?

Mellville
  • 1,027
  • 2
  • 18
  • 39

3 Answers3

0

As the error log says, it seems like you are iterating over an object and not an array. What does the console.log say?

I am assuming that you are not getting an array, but a object.

Another thing is the usage of the getForecast method. The httpClient always returns a Observable, you can only determine the type you expect:

getForecast():Observable<RootObject[]> {
  const url = 'http://api.openweathermap.org/data/2.5/forecast?lat=35&lon=139&APPID=ef48ddb3926ce0283de7291a09fd253e';
  return this.http.get<RootObject[]>(url)
  .pipe(
      retry(3),
      catchError(this.handleError));
}
kauppfbi
  • 805
  • 1
  • 8
  • 24
0

I now had a deeper look into you rest api. Assuming that you want to list always the speed of the wind you have to do the following:

getForecast():Observable<RootObject[]> {
  const url = 'http://api.openweathermap.org/data/2.5/forecast?lat=35&lon=139&APPID=ef48ddb3926ce0283de7291a09fd253e';
  return this.http.get<RootObject[]>(url)
  .pipe(
      map(res => res.list)
      retry(3),
      catchError(this.handleError));
}

in your template:

<ul *ngFor="let obj of foreCast">
  <li>{{obj.wind.speed}}</li>
</ul>
kauppfbi
  • 805
  • 1
  • 8
  • 24
  • wait, im having trouble with the map, i guess i miss an import – Mellville Jun 22 '18 at 11:32
  • I've prepared an example: https://stackblitz.com/edit/angular-1qbdv6 copy the snippets, it will not work in stackblitz directly cause your api is not provided over a secured connection – kauppfbi Jun 22 '18 at 12:21
  • thank you for the support, im sorry for the late reply, i was out of the office, im gonna try your example – Mellville Jun 22 '18 at 13:51
  • wonderful, it works now...I dont know wich answer to vote, feel free to edit or delete any, and thanks again :) – Mellville Jun 22 '18 at 13:56
  • well @fabi_k, your solution works, I get the data rendered, but im not using the interfaces, wich was the main purpose of this post...but thanks anyway – Mellville Jun 22 '18 at 17:03
0

The solution was quite simple: it was all about targeting a nested object and initializing the model

Service.TS:

getForecast(): Observable<RootObject[]> {
    const url = 'http://api.openweathermap.org/data/2.5/forecast?lat=35&lon=139&APPID=ef48ddb3926ce0283de7291a09fd253e';
    return this.http.get<RootObject[]>(url)
    .pipe(
      retry(3),
      catchError(this.handleError));

  }

Component:

forecasts: RootObject[] = []; //Initialize

  constructor(private weatherService: WeatherService) {
    this.getForecast();
  }

  getForecast() {
    this.weatherService.getForecast()
      .subscribe(data => {
        this.forecasts = data;
        console.log(this.forecasts);
      });
  }

And the main problem, rendering the data:

<div class="container" >
  <ul *ngFor="let list of forecasts.list">
      <li>{{list.dt}}</li>
      </ul>
</div>

I was aiming not deep enough because the fetched data is a nested object

Mellville
  • 1,027
  • 2
  • 18
  • 39