error display in *ngfor json array object
Asked Answered
B

5

18

when fetching json array object from rest api and trying to display in ngfor failed with the reason

error

EXCEPTION: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays. in [indexes in HomeComponent@5:37]

Code

import {Component} from 'angular2/core';
import {HomeService} from './home.services';
import {Index} from './index';

@Component({
    selector: 'home-app',
    providers: [HomeService],

    template: `
        <section class="left_side">
            <article>
                <div class="div_home">
                    <div class="div_homeIndxPartition">
                        <div class="div_IndxPartition" *ngFor="#indObj of indexes">
                            <table width="500px" class="idx_cons_table_det">
                                <tr>
                                    <th align="center" color="#A9F5F2"><h3>{{indObj.name}} ({{indObj.tracker}})</h3></th>
                                    <th align="center">Value</th>
                                    <th align="center">Change</th>
                                    <th align="center">%</th>
                                </tr>
                                <tr>
                                    <td align="center" colspan="1"></td>
                                    <td align="center">{{indObj.value}}</td>
                                    <td align="center">{{indObj.change}}</td>
                                    <td align="center">{{indObj.percent}}%</td>
                                </tr>
                            </table>
                            <br/>
                            <table width="500px" class="idx_cons_table">
                                <tr>
                                    <th align="center">High</th>
                                    <th align="center">Low</th>
                                    <th align="center">Open</th>
                                    <th align="center">Close</th>
                                    <th align="center">52 Week High</th>
                                    <th align="center">52 Week Low</th>                             
                                </tr>
                                <tr>
                                    <td align="center">{{indObj.high}}</td>
                                    <td align="center">{{indObj.low}}</td>
                                    <td align="center">{{indObj.open}}%</td>
                                    <td align="center">{{indObj.close}}</td>
                                    <td align="center">{{indObj.yearHigh}}</td>
                                    <td align="center">{{indObj.yearLow}}%</td>
                                </tr>
                            </table>                        
                        </div>                      
                    </div>
                </div>
            </article>
        </section>
    `

})
export class HomeComponent {
    public indexes:Array<Index>=[];
    public error;

constructor(private _service: HomeService){
    this.indexes = _service.getIndexes().subscribe(
            data => this.indexes =  JSON.parse(data),
            error => alert(" Error is : " + error),
            ()=> console.log("finished")
         );
    console.log(this.indexes);
}
}

JSON Data

[
  {
    "id": 1,
    "name": "FTSE 100",
    "ticker": "UKX",
    "value": 69875.23,
    "change": 100,
    "percent": 2.3,
    "high": 69875.23,
    "low": 69700.89,
    "yearHigh": 699999.23,
    "yearLow": 680005.23,
    "open": 69600.54,
    "close": 699000.97,
    "constituents": null,
    "runDate": "21/04/2015"
  },
  {
    "id": 2,
    "name": "FTSE 250",
    "ticker": "MCX",
    "value": 465820.85,
    "change": 100,
    "percent": 2.3,
    "high": 465880.12,
    "low": 465810.74,
    "yearHigh": 478990.34,
    "yearLow": 465320.23,
    "open": 69600.54,
    "close": 699000.97,
    "constituents": null,
    "runDate": "21/04/2015"
  },
  {
    "id": 3,
    "name": "FTSE All-Share",
    "ticker": "ASX",
    "value": 236549.23,
    "change": 100,
    "percent": 2.3,
    "high": 236949.23,
    "low": 236149,
    "yearHigh": 246949.21,
    "yearLow": 235549.29,
    "open": 236519.23,
    "close": 236649.23,
    "constituents": null,
    "runDate": "21/04/2015"
  },
  {
    "id": 4,
    "name": "Euro Stoxx 50",
    "ticker": "STOXX50E",
    "value": 123469.87,
    "change": 100,
    "percent": 2.3,
    "high": 123499.87,
    "low": 123439.87,
    "yearHigh": 123499.87,
    "yearLow": 123169.87,
    "open": 123465.87,
    "close": 123459.87,
    "constituents": null,
    "runDate": "21/04/2015"
  },
  {
    "id": 5,
    "name": "S&P 500 ",
    "ticker": "S500",
    "value": 358976.36,
    "change": 100,
    "percent": 2.3,
    "high": 358986.36,
    "low": 358946.36,
    "yearHigh": 359976.36,
    "yearLow": 357976.36,
    "open": 358970.36,
    "close": 358996.36,
    "constituents": null,
    "runDate": "21/04/2015"
  },
  {
    "id": 6,
    "name": "Dow Jones I.A.",
    "ticker": "INDU",
    "value": 456789.36,
    "change": 100,
    "percent": 2.3,
    "high": 456799.36,
    "low": 456779.36,
    "yearHigh": 456889.36,
    "yearLow": 456689.36,
    "open": 456729.36,
    "close": 456779.36,
    "constituents": null,
    "runDate": "21/04/2015"
  },
  {
    "id": 7,
    "name": "GOLD",
    "ticker": "",
    "value": 500,
    "change": 100,
    "percent": 2.3,
    "high": 700,
    "low": 300,
    "yearHigh": 1500,
    "yearLow": 350,
    "open": 450,
    "close": 470,
    "constituents": null,
    "runDate": "21/04/2015"
  },
  {
    "id": 8,
    "name": "Brent Crude",
    "ticker": "",
    "value": 112,
    "change": 100,
    "percent": 2.3,
    "high": 115,
    "low": 107,
    "yearHigh": 200,
    "yearLow": 72,
    "open": 110,
    "close": 115,
    "constituents": null,
    "runDate": "21/04/2015"
  }
]
Bavaria answered 25/4, 2016 at 11:26 Comment(1)
Use data.json() instead parsing it manually.Carbide
D
9

I think that the value you set in the indexes property isn't an array but an object.

I would see several reasons for this:

  • You receive the response instead of the payload from the getIndexes method. In this case, you could use the map operator in this method:

    getIndexes() {
      return this.http.get(...).map(res => res.json());
    }
    
  • The received payload doesn't correspond to an array but some of its properties. In this case, you need to set this property into the indexes property.

If you want to iterate over the properties of an object, you need to implement a custom filter like this:

@Pipe({name: 'keyValues'})
export class KeysPipe implements PipeTransform {
  transform(value, args:string[]) : any {
    let keys = [];
    for (let key in value) {
      keys.push({key: key, value: value[key]);
    }
    return keys;
  }
}

and use it like that:

<div class="div_IndxPartition" *ngFor="#indObj of indexes | keyValues">
  (...)
</div>

See this question:

Designed answered 25/4, 2016 at 11:29 Comment(5)
Thanks for the response. I'm getting json array and i thought it will be converted back to the domain object by reflection ? Is my understanding wrong ?Bavaria
Using "response.json()" parses the text response payload as json. The corresponding object will be an object...Designed
What is "data"? Howdo you get it?Designed
this.indexes = _service.getIndexes().subscribe( data => this.indexes = JSON.parse(data), error => alert(" Error is : " + error), ()=> console.log("finished") ); data is the json data from server which i have posted in the question last session.Bavaria
what i'm confused is, we cant display the domain object as an array in the *NG and json to domain object will not be done by reflection if u set the property type you are assiging.Bavaria
J
1

You should try this:

In html:

<div  *ngFor="let subsciption of subscriptions;">
                     <div class="col-md-6">
                        <h5 class="widget-title">{{subsciption.name}}</h5>
                    </div>
</div>

in .ts file:

    export class SubscriptionComponent implements OnInit {
        private subscriptions: any =[]; 
        // private subscriptions: any ={};    // here dont use {}
    .
    .
    .
    .
    .

        getAllSubscriptions(queryString) {
            this._http.get(`${environment.base_url}/subscriptions` + queryString)
                .subscribe((response: Response) => {
                    this.subscriptions = response.json();
                },

                (error: Response) => {
                    console.log("Login error");
                });
        }
        this.getAllSubscriptions(query);

    }
Journeywork answered 4/5, 2017 at 13:33 Comment(0)
G
0

I had same problem and my solution was without Pipes. I did not use variable in the template that returns Observer, create intermediate variable and assign result to it. For example, we will save stream to this.sub but result will save to this.indexes on success callback and will use this variable in the html template.

@Component({
  template: `
<ul>
  <li *ngFor="let index of indexs">
    {{ index }}
  </li>
</ul>
`
})
export class HomeComponent {
  privat sub;
  public indexes:Array<Index>=[];
  public error;

  constructor(private _service: HomeService) {
    this.sub = this._service.getIndexes().subscribe(
        data => this.indexes =  JSON.parse(data),
        error => alert(" Error is : " + error),
        () => console.log("finished")
     );

  }
}
Geyser answered 16/10, 2016 at 20:52 Comment(0)
A
0

You don't want to use pipes when working with Observables. This error is very generic and the best way is to throw in a console.log() and see where you are going wrong as it could be numerous things.

My problem was my Array was inside the Object, and I was trying to loop over the Object. Other problems could include the mapping or the ngFor. My console output would look something like this:

this.indexes = _service.getIndexes()
         .subscribe(
            data => {
                this.indexes = JSON.parse(data);
                console.log(indexes);
            },
            error => alert(" Error is : " + error),
                ()=> console.log("finished")
         );
    console.log(this.indexes);

So the fix I needed was something like this:

this.indexes = _service.getIndexes()
             .subscribe(
                data => {
                    this.myNewObject = JSON.parse(data);
                    this.indexes = this.myNewObject.indexes;
                },
                error => alert(" Error is : " + error),
                    ()=> console.log("finished")
             );
        console.log(this.indexes);

This was because the array was nested inside the Object, so I just created a new object and accessed the array by getting its property.

Accelerando answered 24/6, 2017 at 21:36 Comment(0)
B
0

i see your answer, and the easy way to solve is just set the type of the object in the *ngFor to array like this:

public indexes:Array<TYPE_OF_YOUR_DATA>=[];
Balfore answered 19/6, 2019 at 16:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.