0

I've been working on a simple test project, but i happened to come across this really weird problem. I can't access values in an array.

pokemonStats$: Observable<PokemonStats[]>;

getPokemonStats(id: number): any {
this.pokemonStats$
.pipe(take(1))
.subscribe(stats => {
  console.log(stats instanceof Array);
  console.log('length', stats.length);
  console.log('du', stats);
  console.log('test', stats[1]);
});
}

And this is the output:

Output in browser console

What's going on here? A colleague suggested it might be an array-like structure, that's why i added the 'instanceof' log. Any help is greatly appreciated.

EDIT: here's the code, where it gets filled

this.pokemonStats$ = this.getAllPokemonStats(ids);

getAllPokemonStats(ids: number[]): Observable<PokemonStats[]> {
const pokemonArray: PokemonStats[] = [];
ids.forEach(id => {
  const url = 'https://pokeapi.co/api/v2/pokemon/' + id;
  this.http.get(url)
    .pipe(take(1))
    .subscribe((data: PokemonStatsAPI) => {
      pokemonArray.push({
          id: data.id,
          name: data.name,
          speed: data.stats[0].base_stat,
          hp: data.stats[5].base_stat,
          attack: data.stats[4].base_stat,
          defense: data.stats[3].base_stat
        });
    });
});
return of(pokemonArray);

}

Tomas Loksa
  • 95
  • 1
  • 10
  • `pokemonStats$: Observable` In this line you clearly states that `pokemoStats$` is Observable of `PokemonStats[]` in type definition – Developer Jun 30 '20 at 08:01
  • And that's why i subscribed to it, to access the array. But why is it showing length: 0 and why can't I access any of the values, even though they are clearly there when console.logging the entire object? – Tomas Loksa Jun 30 '20 at 08:07
  • The 2nd log entry is interesting as it shows `length 0` but it should be 5 from your next log. Can you show the code where the array is actually created? Or a reproducable example. – x4rf41 Jun 30 '20 at 08:10
  • try doing `JSON.stringify(stats)` and add this json to your question so we can see the raw data in `stats`. – ViqMontana Jun 30 '20 at 08:11
  • Can you try to remove `take(1)`, and then see whats the result. – Developer Jun 30 '20 at 08:12
  • @Viqas is right, i just noticed, you probably fill the array AFTER the console.logs. So it is empty when the log actually happens but the browsers will always show the latest values when you expand it in the log. That is why it logs 0 and stats[1] is undefined but console.log('du', stats); shows the entries – x4rf41 Jun 30 '20 at 08:12
  • @GaurangDhorda same result :/ – Tomas Loksa Jun 30 '20 at 08:15
  • @x4rf41 I added the code, you can check it. – Tomas Loksa Jun 30 '20 at 08:16
  • @Viqas for some reason 'JSON.stringify(stats)' returns just '[]' – Tomas Loksa Jun 30 '20 at 08:17

1 Answers1

2

You're returning the new observable with the pokemonArray, which is empty and will be filled async, therefore when you subscribe to getAllPokemonStats it's empty.

Use the forkJoin operator to perform the http requests and map them using the map operator:

getAllPokemonStats(ids: number[]): Observable<PokemonStats[]> {
  return forkJoin(ids.map(id => {
    return this.http.get(`https://pokeapi.co/api/v2/pokemon/${id}`);
  })).pipe(
    map(results => results.map(data => ({
      id: data.id,
      name: data.name,
      speed: data.stats[0].base_stat,
      hp: data.stats[5].base_stat,
      attack: data.stats[4].base_stat,
      defense: data.stats[3].base_stat
    }))),
  );
}
cyr_x
  • 13,987
  • 2
  • 32
  • 46