尝试* ngFor Json对象时出错

时间:2018-08-07 17:59:16

标签: angular typescript angular-material-6

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

  

错误错误:“无法找到类型为'object'的其他支持对象'[object Promise]'。NgFor仅支持绑定到数组等Iterable。”

不过,据我所见,您可以在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;
    }
}

6 个答案:

答案 0 :(得分: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>

这是如此新,您必须使用最新版本的Angular6。如果您已经在Angular 6上运行,则只需运行:

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

获取最新消息。

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

答案 1 :(得分:0)

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

currenciesJson = {};

在这里将其初始化为对象。

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

在这里,您将其初始化为一个承诺。

所以这可能行不通。它必须是一个数组。

我强烈建议您阅读the guide about HTTP,以了解如何正确使用HttpClient来获取数据。您不应该使用promise,尤其是使用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);

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

答案 2 :(得分:0)

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

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>

答案 3 :(得分: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);
    })
}

答案 4 :(得分:0)

* ngFor仅用于遍历数组,而不用于对象,您的响应包含具有status(对象)和data(对象数组)的对象。您可以像这样循环遍历对象数组。

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()遍历对象键,但是我认为您的问题是遍历“数据”而不是“键”

答案 5 :(得分:0)

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

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

这很hacky,但是那很好。如果我要回到这个问题上,我肯定会改进很多,但确实有效。

这是这三个文件的来源。

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>