#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;
});
}