2

我正在尝试创建一个从端点返回的数据列表,我得到了 10 位数据,我想使用 *ngFor 来显示它们。我已经在正确的时间正确输入了数据,但它说

错误错误:“找不到类型为'object'的不同支持对象'[object Promise]'。NgFor 仅支持绑定到Iterables,例如数组。”

但是,据我所见,您可以在最新版本的 Angular 中在 *ngFor 中使用 json。

JSON 返回:https ://pastebin.com/TTn0EqSS

app.component.html

<div [class.app-dark-theme]="true">
    <mat-sidenav-container fullscreen class="sidenav-container">
        <mat-toolbar class="toolbar">
            Coin Market Cap 3rd party api app
        </mat-toolbar>

        <mat-card>
            <mat-card-header>
                <mat-card-title>CryptoCurrency Market Overview</mat-card-title>
                <mat-card-subtitle>Top 15 current currencies.</mat-card-subtitle>
            </mat-card-header>

            <mat-card-content class="currency-listings">
                <div *ngIf="finishedLoading">
                    <mat-grid-list cols="1" rowHeight="2:1">
                        <mat-grid-tile *ngFor="let currency of currenciesJson; let i = index" (click)="selectCurrency(i)"> 
                            {{currency.data[i].name}}
                        </mat-grid-tile>
                    </mat-grid-list>

                    test 
                    test
                    test
                </div>
            </mat-card-content>
        </mat-card>

        <!--    (click)="showInfo(true)"   -->

        <mat-card *ngIf="displayInfo">
            test
        </mat-card>
    </mat-sidenav-container>
</div>

coin-market-cap.service.ts

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

@Injectable()
export class CoinMarketCapService 
{   
    key = "REDACTED";   
    apiUrl = 'https://pro-api.coinmarketcap.com/v1/cryptocurrency/';

    constructor(public http: HttpClient) { }

    getCurrencies(totalCurrencies: number)
    {
        let promise = new Promise((resolve, reject) => {
            let url = this.apiUrl + "listings/latest?limit=" + totalCurrencies + "&CMC_PRO_API_KEY=" + this.key;
            this.http.get(url)
            .toPromise()
            .then(
            res => { 
                console.log(res);
                resolve();
            });
        })
        return promise;
    }

    getCurrency(currencyId: number)
    {
        console.log("in getcurrency");
        let url = this.apiUrl + "info?id=" + currencyId + "&CMC_PRO_API_KEY=" + this.key;
        console.log(url);
        return this.http.get(url);
    }
}

app.component.ts

import { Component } from '@angular/core';
import { CoinMarketCapService } from '../services/coin-market-cap.service';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent 
{   
    currenciesJson = {};
    displayInfo = false;
    finishedLoading = false;

    constructor(private CoinMarketCapService: CoinMarketCapService) {}

    ngOnInit()
    {
        console.log(this.currenciesJson);
        this.currenciesJson = this.CoinMarketCapService.getCurrencies(10)
        .then(res => 
            this.finishedLoading = true
        )
        console.log(this.currenciesJson);
        console.log("exiting ngoninit");
    }

    selectCurrency(currencyId: number)
    {
        console.log(currencyId);
        let currencyObject = this.CoinMarketCapService.getCurrency(currencyId);
    }

    showInfo ( showInfo: boolean )
    {
        this.displayInfo = showInfo;
    }
}
4

6 回答 6

3

在 Angular 6.1.something(最近发布)中有一个用于迭代 JSON 对象的管道。

它调用 KeyValuePipe - 文档在这里 - https://angular.io/api/common/KeyValuePipe

<div *ngFor="let item of object | keyvalue">
  {{item.key}}:{{item.value}}
</div>

这太新了,您必须使用最新版本的 Angular 6。如果您已经使用 Angular 6,那么只需运行:

ng update @angular/core
ng update @angular/cli

获取最新信息。

这是一篇关于它的文章 - http://www.talkingdotnet.com/angular-6-1-introduces-new-keyvalue-pipe/

于 2018-08-07T20:24:24.317 回答
0

ngFor 遍历数组。但请阅读您的代码:

currenciesJson = {};

在这里,您将它初始化为一个对象。

this.currenciesJson = this.CoinMarketCapService.getCurrencies(10)
    .then(res => 
        this.finishedLoading = true
    )

在这里你将它初始化为一个承诺。

所以这不可能奏效。它必须是一个数组。

我强烈建议您阅读有关 HTTP 的指南,以了解如何正确使用HttpClient来获取数据。你不应该使用 Promise,尤其是你使用它们的方式,这并不完全正确,而且充满了反模式。它应该归结为:

getCurrencies(totalCurrencies: number): Observable<Array<Currency>> {
    const url = this.apiUrl + "listings/latest?limit=" + totalCurrencies + "&CMC_PRO_API_KEY=" + this.key;
    return this.http.get<Array<Currency>>(url);
}

并且,在组件中:

currenciesJson: Array<Currency> = [];
...

this.CoinMarketCapService.getCurrencies(10).subscribe(currencies => this.currenciesJson = currencies);

请注意指定类型如何让编译器告诉您代码中的所有错误。

于 2018-08-07T18:03:33.053 回答
0

首先避免初始化:
将 ngOnInit 方法改为 currenciesJson: object;currenciesJson = {};

ngOnInit()
    {
        this.CoinMarketCapService.getCurrencies(10)
        .then(res => {
            this.currenciesJson = res
            this.finishedLoading = true
        });
    }

编辑

<mat-grid-tile *ngFor="let currency of currenciesJson.data; let i = index" (click)="selectCurrency(i)"> 
       {{currency.name}}
</mat-grid-tile>
于 2018-08-07T18:03:47.387 回答
0

解决此问题的最简单方法是创建一个 TypeScript 模型对象以将传入的 json 文件映射到。

例如,使用您自己的 Json 对象中的键:

export class CurrencyModel {
    currency: string;
    foo: number;
    bar: number;
    constructor(currency: string, foo: number, bar: number) {
        this.currency = currency;
        this.foo = foo;
        this.bar = bar;
    }

}

然后您将使用以下命令创建对象模型的新实例:

currencyData: CurrencyModel;
getCurrency(currencyId: number)
{
    console.log("in getcurrency");
    let url = this.apiUrl + "info?id=" + currencyId + "&CMC_PRO_API_KEY=" + this.key;
    console.log(url);
    response = this.http.get(url);
    response.subscribe(data => {
        this.currencyData = data;
    }, error1 => {
        console.log(error1);
    })
}
于 2018-08-07T18:08:06.180 回答
0

*ngFor 仅用于迭代数组,而不是对象,您的响应包含一个具有状态(对象)和数据(对象数组)的对象。您可以像这样遍历对象数组。

this.currenciesJson = {
  status : {},
  data: [{}]
}

您只能遍历currencyJson.data

尝试设置

<mat-grid-tile *ngFor="let currency of currenciesJson.data; let i = index" (click)="selectCurrency(currency)"> 
   {{currency.name}}
 </mat-grid-tile>

此外,如果使用 angular 6.1,您可以通过 keyValue pipr 循环对象键,如果使用 angular 5,则可以使用 Object.keys() 循环,但我认为您的问题是循环遍历“数据”而不是“键”

于 2018-08-07T19:09:44.033 回答
0

在这篇文章的评论/答案的帮助下,我达到了我想要的程度。

这里使用了 Angular 6.1s 的新键值管道。 https://angular.io/api/common/KeyValuePipe

它非常hacky,但它的用途很好。如果我回到这里,我肯定会改进很多,但它确实有效。

这是 3 个文件的来源。

app.component.ts

import { Component } from '@angular/core';
import { CoinMarketCapService } from '../services/coin-market-cap.service';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent 
{   
    currenciesJson: object;
    selectedCurrency: object;
    displayInfo: boolean = false;
    finishedLoading: boolean = false;

    constructor(private CoinMarketCapService: CoinMarketCapService) {}

    ngOnInit()
    {
        this.CoinMarketCapService.getCurrencies(15)
        .then(res => {
            this.currenciesJson = res,
            this.finishedLoading = true;
        });
    }

    selectCurrency(currencyId: number)
    {
        this.CoinMarketCapService.getCurrency(currencyId)
        .then( res => {
            this.selectedCurrency = res,
            this.showInfo(true)
        })
    }

    showInfo ( showInfo: boolean )
    {
        this.displayInfo = showInfo;
    }
}

coin-market-cap.service.ts

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

@Injectable()
export class CoinMarketCapService 
{   
    key: string = "REDACTED"; // https://pro.coinmarketcap.com/ free 6000 requests per month.   
    apiUrl: string = 'https://pro-api.coinmarketcap.com/v1/cryptocurrency/';

    constructor(public http: HttpClient) { }

    getCurrencies(totalCurrencies: number)
    {
        let promise = new Promise((resolve, reject) => {
            let url: string = this.apiUrl + "listings/latest?sort=market_cap&cryptocurrency_type=coins&limit=" + totalCurrencies + "&CMC_PRO_API_KEY=" + this.key;
            this.http.get(url)
            .toPromise()
            .then(
            res => { 
                resolve(res);
            });
        })
        return promise;
    }

    getCurrency(currencyId: number)
    {
        let promise = new Promise((resolve, reject) => {
            let url: string = this.apiUrl + "info?id=" + currencyId + "&CMC_PRO_API_KEY=" + this.key;
            this.http.get(url)
            .toPromise()
            .then(
            res => { 
                resolve(res);
            });
        })
        return promise;
    }
}

app.component.html

<div [class.app-dark-theme]="true">
    <mat-sidenav-container fullscreen class="sidenav-container">
        <mat-toolbar class="toolbar">
            Coin Market Cap 3rd party api app
        </mat-toolbar>

        <mat-card>
            <mat-card-header>
                <mat-card-title>CryptoCurrency Market Overview</mat-card-title>
                <mat-card-subtitle>Top 15 current currencies.</mat-card-subtitle>
            </mat-card-header>

            <mat-card-content>
                <div *ngIf="finishedLoading">
                    <mat-grid-list cols="1" rowHeight="40px">
                        <mat-grid-tile *ngFor="let currency of currenciesJson.data | keyvalue; let i = index" 
                                (click)="selectCurrency(currency.value.id)" class="grid-tile"> 
                            {{currency.value.name}}
                        </mat-grid-tile>
                    </mat-grid-list>
                </div>
            </mat-card-content>
        </mat-card>

        <mat-card *ngIf="displayInfo">  
            <mat-card-header>
                <mat-card-title>Selected Cryptocurrency Details</mat-card-title>
                <mat-card-subtitle>Name and links of selected currency</mat-card-subtitle>
            </mat-card-header>

            <mat-card-content *ngFor="let currency of selectedCurrency.data | keyvalue; let i = index">
                Name: {{currency.value.name}} <br><br>
                Ticker Symbol: {{currency.value.symbol}}<br><br>
                Website: {{currency.value.urls.website}}<br><br>
                Source Code: {{currency.value.urls.source_code}}<br><br>
                Twitter: {{currency.value.urls.twitter}}
            </mat-card-content>
        </mat-card>
    </mat-sidenav-container>
</div>
于 2018-08-08T00:52:24.877 回答