Извлечение данных из API для источника данных компонента

#angular #typescript

#angular #typescript

Вопрос:

Я пытаюсь извлечь данные из API, используя существующий пакет узла под названием pokeapi-js-wrapper . Я немного новичок в Angular, поэтому не уверен, правильно ли я подхожу к этому. Я построил сервис следующим образом (сами данные являются заполнителем).

 import { Injectable } from '@angular/core';
import { Pokedex } from "pokeapi-js-wrapper";
import { Pokemon } from 'src/Pokemon';

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

  api: Pokedex;
  pokemon: Pokemon[];

  constructor() {
    this.api = new Pokedex();
  }

  getAllPokemon() {
    console.log("all pokemon", this.pokemon); //PROBLEM #1
    return this.api.getPokemonsList().then((response) => {
      this.pokemon.push(response.results.map(p => {
        return {
          name: p.name,
          number: 0,
          evolutionLink: "#",
          movesetLink: "#"
        } as Pokemon;
      }));
    });
  }
}
  

На данный момент у меня есть 2 проблемы, с которыми я сталкиваюсь, возможно, связанные.

Проблема № 1: this.pokemon не работает. Я забываю о масштабах this в этой области? У console.log , который я включил, есть выходные данные all pokemon undefined . Что я здесь делаю не так?

Проблема № 2: Как я могу извлечь эти данные для использования в моем компоненте? Я определил компонент следующим образом:

 import { Component, OnInit } from '@angular/core';
import { Pokemon } from 'src/Pokemon';
import { PokeApiService } from 'src/app/poke-api.service';

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

  pokemon: Pokemon[] = [];
  columnsToDisplay: string[] = ["number", "name", "moveset-link", "evolution-info"];

  constructor(private pokeApiService: PokeApiService) {
    pokeApiService.getAllPokemon().then(function (response) {
      this.pokemon = response; //PROBLEM #2
    });
  }

  ngOnInit() {
  }

}


  

Когда я получу ответ от службы, смогу ли я просто установить его в качестве источника данных для моей таблицы? Для дополнительного контекста я использую Angular Material, а шаблон определяется следующим образом:

 <h1>Pokémon List</h1>

<table mat-table [dataSource]="pokemon" class="mat-elevation-z8">
    <tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
    <tr mat-row *matRowDef="let row; columns: columnsToDisplay"></tr>
    <ng-container matColumnDef="number">
        <th mat-header-cell *matHeaderCellDef> Number </th>
        <td mat-cell *matCellDef="let pokemon"> {{pokemon.number}} </td>
    </ng-container>
    <ng-container matColumnDef="name">
        <th mat-header-cell *matHeaderCellDef> Name </th>
        <td mat-cell *matCellDef="let pokemon"> {{pokemon.name}} </td>
    </ng-container>
    <ng-container matColumnDef="moveset-link">
        <th mat-header-cell *matHeaderCellDef> Moveset Info </th>
        <td mat-cell *matCellDef="let pokemon"> <a mat-stroked-button color="primary"
                [href]="pokemon.movesetLink">Moveset</a> </td>
    </ng-container>
    <ng-container matColumnDef="evolution-info">
        <th mat-header-cell *matHeaderCellDef> Evolution Info </th>
        <td mat-cell *matCellDef="let pokemon"> <a mat-stroked-button color="primary"
                [href]="pokemon.evolutionLink">Evolution Info</a></td>
    </ng-container>
</table>
  

Комментарии:

1. Вы объявляете массив Pokemon, но вам нужно создать его экземпляр в конструкторе. это. Pokemon = новый массив<Покемон>(). После этого вы можете помещать значения в массив.

2. Для # 2, если ответ действительно представляет собой массив Pokemon, он будет доступен в вашем шаблоне. Вам следует сначала попробовать выполнить итерацию результирующего набора, прежде чем использовать материальный компонент. *ngFor=»пусть p покемонов».

Ответ №1:

Для # 1: вам нужно не только объявить тип свойства класса, но и присвоить ему значение / инициализировать его. Объявленная переменная остается неопределенной, поскольку она не определена.

 export class PokeApiService {

  api: Pokedex;
  pokemon: Pokemon[]; // this only declares the type but no value is assigned

  constructor() {
  }

  ngOnInit() {
    this.pokemon = []; // init the property with empty array value;
    this.api = new Pokedex();
  }

}
  

Вы можете инициализировать значения внутри конструктора или внутри соответствующего перехвата жизненного цикла компонента Angular (например, ngOnInit)

# 2: Проблема возникает из-за того, что вы используете неназванную функцию, которая создает свою собственную область выполнения (и ‘this’), и строка this.pokemon пытается найти переменную ‘pokemon’ внутри этой области выполнения. Для исправления вам нужно использовать функцию arrow, как показано ниже, функции arrow не создают свою собственную область выполнения и «прозрачно» могут обращаться к внешней области выполнения (в данном случае к классу, который содержит ‘pokemon’:

   constructor(private pokeApiService: PokeApiService) {
    pokeApiService.getAllPokemon().then((response) => { // use arrow function to prevent this.pokemon pointing at the unnamed function scope;
      this.pokemon = response;
    });
  }