1

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.

6
  • why is there a ? in let hole of course?.holes Commented Jan 19, 2017 at 19:12
  • @MiteshPant: Safe operator for data that is received async, so app won't throw error for loading view before data has arrived :) Commented Jan 19, 2017 at 19:15
  • syntaxsuccess.com/viewarticle/elvis-operator-in-angular-2.0 Commented Jan 19, 2017 at 19:15
  • @AlanHay yeah, you should be able to use the elvis-operator in this case. How does your data look like.... is holes in fact an array? Commented Jan 19, 2017 at 19:20
  • 1
    The input above the loop works without any issues. Course is a TS class wrapping some JSON. I can iterate the array 'holes' in the TS class without any issues to provide calculated values. Updating a value in the standalone input correctly updates the corresponding model value and the calculated value is updated as expected. Commented Jan 19, 2017 at 19:25

1 Answer 1

1

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
                }
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Well, this is why I asked if holes is an array... ;) But good that you figured out the solution! :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.