bluePearl
bluePearl

Reputation: 1257

Error rendering json file in ngFor

I am looping through a json file to display data in panels. But i am having some trouble controlling how to display the data appropriately. This is my json data that is returned from the services:

Object {Group1: Object, 
        Group2: Object}

The json file data sample:

{
  "Group1": {
      "name": "Group1List",
      "dataFields": [..],
      "dataQuery": {..},
      "id": 1,
      "title": "Group1",
      "content": {..}
    },
}

This is my services:

getGroupsData(){
        return this._http.get('...')
        .map((res:Response) => res.json())
    }

Component.ts:

 groups: Array<any> = [];
 getGroups(){
    this.groupService.getGroupsData().subscribe(
      data => this.groups = data;
  }

HTML:

<div dnd-sortable-container [sortableData]="groups" [dropZones]="['container-dropZone']">
        <div class="col-sm3" *ngFor="let group of groups; let i = index" dnd-sortable [sortableIndex]="i" [dragEnabled]="dragOperation">
            <div class="panel panel-primary" dnd-sortable-container [dropZones]="['widget-dropZone']">
                <div class="panel-heading"></div>
                <div class="panel-body"></div>
            </div>
        </div>
    </div>

when i render the code i get an error in the console stating: Error trying to diff '[object Object]' in the heading i would like to add Group1 and then in the body i will display different parts from the json.

What is the source of the problem?

Upvotes: 0

Views: 112

Answers (3)

Murhaf Sousli
Murhaf Sousli

Reputation: 13296

*ngFor requires an array [], and you are passing an object

Your sample has unnecessary nested level, flat is always better

Your json should look like this

[
   {
     "name": "Group1List",
     "dataFields": [..],
     "dataQuery": {..},
     "id": 1,
     "title": "Group1",
     "content": {..}
   },
   {
     "name": "Group2List",
     "dataFields": [..],
     "dataQuery": {..},
     "id": 2,
     "title": "Group2",
     "content": {..}
   },
   // ....
]

Update:

If you have no control over your json scheme, try to flatten it here

getGroupsData(){
    return this._http.get('...')
    .map((res:Response) => res.json())
    .map((obj) => Object.keys(obj).map((key)=>{ return obj[key]})
}

or implement a pipe that iterate over object properties

import { PipeTransform, Pipe } from '@angular/core';

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

and use it like this

<div *ngFor="let group of groups | keys; let i = index">

</div>

Upvotes: 0

Frank Modica
Frank Modica

Reputation: 10526

*ngFor requires an array, but it looks like you are passing it an object.

If you cannot change the JSON response, and you know the names of the groups beforehand, you can place the objects in an array:

this.groups = [data.Group1, data.Group2, // etc]

Upvotes: 1

snorkpete
snorkpete

Reputation: 14574

Change your component to:

groups: Array<any> = [];
 getGroups(){
    this.groupService.getGroupsData().subscribe(
      data => this.groups = data.Group1.dataFields;
  }

Why?

Because, you want your groups component property to be an array. So, in your subscribe handler, data will refer to the entire JSON object, and you only care about the Group1 property of your results.

Upvotes: 0

Related Questions