Alan Hay
Alan Hay

Reputation: 23226

Error iterating nested Array property of Object using *ngFor

I am trying to iterate over an Array property of an object as below:

<p>
  Editing Course : {{course?.name}}<br/>
  Course Outward Par : {{course?.getOutwardPar('MEDAL')}}<br/>
  Course Outward Yards : {{course?.getOutwardYards('MEDAL')}}
</p>

<div class="container">
  <h1>Course Form</h1>
  <form (ngSubmit)="onSubmit()" #heroForm="ngForm">
    <div class="form-group">
      <table>
        <tr>
          <td><label for="name">Name</label></td>
          <td><input type="text" class="form-control" id="name" name="name" required
                     [(ngModel)]="course && course.name">
          </td>
        </tr>

        <tr>
          <input type="number" class="form-control" id="hole1" name="hole1" required
                 [(ngModel)]="course && course.holes[1].tees['MEDAL'].par">
        </tr>

        <!-- 
             --- BROKEN HERE---
         -->
        <tr *ngFor="let hole of course?.holes">
          <td>{{hole.name}}</td>
        </tr>

      </table>
    </div>

    <button type="submit" class="btn btn-default">Submit</button>
  </form>
</div>

Everything prior to the *ngFor works as expected including the below so the property holes of course can surely be considered to be an array. No?

<input type="number" class="form-control" id="hole1" name="hole1" required
                     [(ngModel)]="course && course.holes[1].tees['MEDAL'].par">

The ngFor triggers the error:

Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.

There is some dicusssion here https://github.com/angular/angular/issues/6392 on the subject. The post by robwormald suggests that the ? opertaor can be used in such cases.

Upvotes: 1

Views: 1407

Answers (1)

Alan Hay
Alan Hay

Reputation: 23226

Okay it appears Angular 2 does not support using associative arrays / Dictionaries in *ngFor

e.g. JSON with the structure below.

See for example:

Iterate over TypeScript Dictionary in Angular 2

I could get this to work by simply creating a keys variable in the Component and iterating that. Other solutions propose using a Directive but that's for later.

e.g.

keys: string [];
this.keys = Object.keys(this.course.holes);

and iterating the keys

<tr *ngFor="let key of keys">
  <td>{{key}}</td>
  <td>{{course.holes[key].name}}</td>
  <td>
    <input type="number" class="form-control" id="hole{{key}}" name="holePar{{key}}"
           [(ngModel)]="course && course.holes[key].tees['MEDAL'].par"/>
  </td>
  <td>

        <input type="number" class="form-control" id="hole{{key}}" name="holeLength{{key}}"
               [(ngModel)]="course && course.holes[key].tees['MEDAL'].length"/>
      </td>
    </tr>

Source JSON:

{
    "name": "Ny Course",
    "courseTeeSets": [],
    "holes": {
        "1": {
            "id": 1,
            "number": 1,
            "name": "Hole Number 1",
            "tees": {
                "MEDAL": {
                    "id": 3,
                    "teeType": "MEDAL",
                    "length": 100,
                    "strokeIndex": 15,
                    "par": 8
                },
                "MENS": {
                    "id": 1,
                    "teeType": "MENS",
                    "length": 509,
                    "strokeIndex": 15,
                    "par": 5
                },
                "LADIES": {
                    "id": 2,
                    "teeType": "LADIES",
                    "length": 489,
                    "strokeIndex": 15,
                    "par": 5
                }
            }
        },
        "2": {
            "id": 2,
            "number": 2,
            "name": "Hole Number 2",
            "tees": {
                "MEDAL": {
                    "id": 4,
                    "teeType": "MEDAL",
                    "length": 110,
                    "strokeIndex": 9,
                    "par": 8
                },
                "MENS": {
                    "id": 6,
                    "teeType": "MENS",
                    "length": 191,
                    "strokeIndex": 9,
                    "par": 4
                },
                "LADIES": {
                    "id": 5,
                    "teeType": "LADIES",
                    "length": 171,
                    "strokeIndex": 9,
                    "par": 4
                }
            }
        }
    }
}

Upvotes: 1

Related Questions