0

The below code returns an empty array, and I'm having trouble understanding why. What is the standard practice for pushing objects to an array from a return Observable?

In jobServices.ts:

 getCities(city){
  return this.http.get(`http://api.openweathermap.org/data/2.5/weather?q=${city}&appid=70d86e78cabf44f710fd89936c709750`)
 }

In Home.ts

cities = ["Atlanta", "Chicago", "New York", "Los Angeles", "San 
   Diego", "Athens", "Miami", "Nashville", "Austin", "Amsterdam", 
   "Paris" ]
citiesPayload = []



constructor(public jobService: JobService) { }

ngOnInit() {
    this.returnCities();
}

returnCities(){
    for (var i = 0; i < this.cities.length; i++){
        this.jobService.getCities(this.cities[i])
            .subscribe(city => {
                this.citiesPayload.push(city);
            });
        }
    console.log(this.citiesPayload)
}

1 Answer 1

3

Try something like this, you need to add the HTTP requests into an array then use an operator like forkJoin. Then you can subscribe to that newly returned stream.

import {
  forkJoin
} from 'rxjs';
class ExampleClass {
  cities = [
    "Atlanta",
    "Chicago",
    "New York",
    "Los Angeles",
    "San Diego",
    "Athens",
    "Miami",
    "Nashville",
    "Austin",
    "Amsterdam",
    "Paris"
  ];
  constructor(public jobService: JobService) {}




  ngOnInit() {
    this.returnCities()
  }

  returnCities() {
    const cityObservables = [];
    for (var i = 0; i < this.cities.length; i++) {
      cityObservables.push(this.jobService.getCities(this.cities[i]));
    }
    forkJoin(cityObservables).subscribe(resp => {
      // city data here
      console.log(resp);
    });
  }

  getCities(city) {
    return this.http.get(`http://api.openweathermap.org/data/2.5/weather?q=${city}&appid=70d86e78cabf44f710fd89936c709750`)
  }
}

Adding a stackblitz-demo included are the suggestions of @RichardMatsen & @eric99.

import {
  Component,
  OnInit
} from '@angular/core';
import {
  HttpClient
} from '@angular/common/http';

import {
  Observable,
  forkJoin,
  of
} from 'rxjs';
import {
  catchError
} from 'rxjs/operators';


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

  todos: number[] = [1, 3, 5, 7, 9];
  viewValues: Todo[];

  constructor(private http: HttpClient) {}

  ngOnInit() {
    this.getTodos();
  }

  getTodos() {
    const todos = this.todos.map(t => this.http.get < Todo > (`https://jsonplaceholder.typicode.com/todos/${t}`));
    forkJoin(todos).pipe(catchError(err => of (err))).subscribe(resp => this.viewValues = resp);
  }
}


export interface Todo {
  userId: number;
  id: number;
  title: string;
  completed: boolean;
}
Sign up to request clarification or add additional context in comments.

3 Comments

Perhaps use Array.map like this const cityObservables = this.cities.map(city => this.jobService.getCities(city)) or shorter equivalent const cityObservables = this.cities.map(this.jobService.getCities)
Note that forkJoin is fragile - if one of the cities is unknown, you get nothing in the subscribe. Add this.http.get(...).pipe(catchError(err => of(err) )) to handle individual get errors.
@RichardMatsen & eric99 excellent suggestions. I've updated for posterity.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.