Обработка нескольких Angular наблюдаемых - PullRequest
1 голос
/ 26 апреля 2020

Я новичок с Angular и TypeScript, поэтому я создаю свое собственное приложение, используя API-интерфейс publi c Pokemon для практики. Тем не менее, я хочу получить отзывы об этой задаче, чтобы использовать http для получения информации о покемонах с идентификаторами между [1, 50]. Чтобы получить покемона для каждого идентификатора, мне нужен отдельный запрос HTTP GET. В результате у меня есть 50 наблюдаемых объектов, на которые мне нужно подписаться, а затем сгенерировать массив из результатов всех 50 наблюдаемых. Тем не менее, я хочу получить совет о том, есть ли лучший способ достичь того, на что я надеюсь.

poke-dashboard.component.ts (код для подписки на 50 наблюдаемых)

import { Component, OnInit } from '@angular/core';
import { PokemonService } from '../services/pokemon.service';
import { Pokemon } from '../shared/pokemon';

@Component({
  selector: 'app-poke-dashboard',
  templateUrl: './poke-dashboard.component.html',
  styleUrls: ['./poke-dashboard.component.scss'],
})
export class PokeDashboardComponent implements OnInit {
  pokemons: Pokemon[];

  constructor(private pokemonservice: PokemonService) {}

  ngOnInit(): void {
    let pokemonsList: Pokemon[] = [];
    for (var i = 1; i <= 50; i++) {
      this.pokemonservice.getPokemonForId(i).subscribe((data: any) => {
        pokemonsList.push(this.pokemonservice.generatePokemon(data));
      });
    }
    this.pokemons = pokemonsList;
  }
}

pokemon.service.ts (код для обработки вызовов http )

import { Injectable } from '@angular/core';
import { Pokemon } from '../shared/pokemon';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class PokemonService {
  baseUrl: string;
  private pokemons: Pokemon[] = [
    new Pokemon(
      'pikachu',
      'pikachu',
      90,
      50,
      50,
      40,
      55,
      35,
      'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/25.png'
    ),
  ];
  constructor(private httpClient: HttpClient) {
    this.baseUrl = 'https://pokeapi.co/api/v2/';
  }

  public getPokemonForId(id: number): Observable<any> {
    return this.httpClient.get(this.baseUrl + `pokemon/${id}`);
  }

  public generatePokemon(pokeinfo: any): Pokemon {
    return new Pokemon(
      pokeinfo['name'],
      pokeinfo['species']['name'],
      pokeinfo['stats'][0]['base_stat'],
      pokeinfo['stats'][1]['base_stat'],
      pokeinfo['stats'][2]['base_stat'],
      pokeinfo['stats'][3]['base_stat'],
      pokeinfo['stats'][4]['base_stat'],
      pokeinfo['stats'][5]['base_stat'],
      pokeinfo['sprites']['front_default']
    );
  }

  public getPokemons() {
    return this.pokemons;
  }
}

1 Ответ

2 голосов
/ 29 апреля 2020

Если вы начинаете с Angular и Rx JS, я бы не рекомендовал PokeAPI изучать его. Немного сложно получить информацию от.

Тем не менее, в результате она содержит гипертекстовые медиа. Вместо использования for l oop вы можете получить URL для каждого идентификатора, используя этот гипертекстовый носитель. Запрос GET на URL https://pokeapi.co/api/v2/pokemon/?limit=3&offset=0 извлекает следующий результат.

{
  "count": 964,
  "next": "https://pokeapi.co/api/v2/pokemon/?offset=3&limit=3",
  "previous": null,
  "results": [
    {
      "name": "bulbasaur",
      "url": "https://pokeapi.co/api/v2/pokemon/1/"
    },
    {
      "name": "ivysaur",
      "url": "https://pokeapi.co/api/v2/pokemon/2/"
    },
    {
      "name": "venusaur",
      "url": "https://pokeapi.co/api/v2/pokemon/3/"
    }
  ]
}

Вы можете сделать запрос с параметром limit=50, если вам нужны первые 50 записей. Теперь мы можем получить все URL-адреса и сделать HTTP-запросы. Вместо индивидуальной подписки мы могли бы использовать Rx JS forkJoin, что позволяет нам подписываться на несколько наблюдаемых.

Если вы начинаете с Angular, это может немного слишком много. Я бы сказал go по одному за раз. Я бы порекомендовал вам начать с Angular Tutorial . Он знакомит с основами.

Рабочий пример: Stackblitz

pokemon-api.service.ts

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

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

export const BASE_URL = 'https://pokeapi.co/api/v2';

@Injectable()
export class PokemonApiService {

  constructor(private httpClient: HttpClient) { }

  public getListOfPokemon(limit: string, offset ?: string) {
    const params = new HttpParams()
      .set('offset', offset ? offset : '0')
      .set('limit', limit);
    return this.httpClient
      .get<any>(`${BASE_URL}/pokemon`, { observe: 'response', params: params })
      .pipe(
        map(res => res.body.results),
        catchError(error => of(error.url))
      );
  }

  public getPokemonDetails(urlList: Array<any>) {
    urlList = urlList.map(url => this.httpClient.get<any>(url));
    return forkJoin(urlList);
  }
}

app.component.ts

import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { map, catchError, tap } from 'rxjs/operators';

import { PokemonApiService } from './pokemon-api.service';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  pokemons = [];
  limit = '50';

  constructor(private _pokemonApiService: PokemonApiService) {}

  ngOnInit(){
    this.getPokemonList();
  }

  private getPokemonList() {
    this._pokemonApiService.getListOfPokemon(this.limit).subscribe(
      response => { this.getPokemonDetails(response.map(response => response.url)); },
      error => { console.error(error); }
    );
  }

  private getPokemonDetails(urlList: Array<string>) {
    this._pokemonApiService.getPokemonDetails(urlList).subscribe(
      response => { this.pokemons = response; },
      error => { console.error(error); }
    );
  }

}

app.component. html

<table>
  <tr>
    <th>ID</th>
    <th>Name</th>
    <th>Sprite</th>
  </tr>
  <tr *ngFor="let pokemon of pokemons">
    <td>{{ pokemon.id }}</td>
    <td>{{ pokemon.name | titlecase }}</td>
    <td><img [src]="pokemon.sprites.front_default"/></td>
  </tr>
</table>
...