Esoemah Esoemah - 6 months ago 65
JSON Question

Looping over JSON array using *ngFor

I currently have the following JSON file:

[
{
"Arsenal": {
"form": {
"away": 4.6064800860172,
"home": 2.2108841763771
},
"stadium": "Stadium 1"
}
},
{
"Man City": {
"form": {
"away": 4.9473459270023,
"home": 5
},
"stadium": "Stadium 2"
}
},
{
"Man Utd": {
"form": {
"away": 5,
"home": 3.2296790061981
},
"stadium": "Stadium 3"
}
}
]


and I want to display this data in a table. I currently have a service that retrieves the JSON file and returns it

public getJSON(): Observable<any> {
return this.http.get('assets/teams.json')
.map(
(response: Response) => {
const data = response.json();
return data;
}
);
}


I then subscribe to it in my component and save it to
teams
.

teams = [];
loadJSON() {
this.teamService.getJSON().subscribe(
(teams: any[]) => this.teams = teams,
(error) => console.log(error)
);
}


and using the following
HTML


<div class="container">
<table class="table">
<thead>
<tr>
<th>Team</th>
<th>Home</th>
<th>Away</th>
<th>Stadium</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let team of teams | keys">
<td>{{ (team.value | keys)[0].key }}</td>
<td>{{ (team.value | keys)[0].value["form"]["home"] }}</td>
<td>{{ (team.value | keys)[0].value["form"]["away"] }}</td>
<td>{{ (team.value | keys)[0].value["stadium"] }}</td>
</tr>
</tbody>
</table>
</div>


gives the table seen below

Table showing JSON file

Surely there must be a better way of doing this? How can I do this in a more straight-forward way, that is a lot more readable? For example, if the key was actually "Arsenal", "Man City" and "Man Utd" instead of 0, 1 and 2 respectively, it would be much more readable. Why does it have those keys instead? I'm used to coding in Python so it doesn't really make much sense to me.

A working stackblitz can be found here.

Answer Source

I propose to have your own Team object and map your JSON on it.

So in your teams.service you have:

public getJSON(): Observable<Team[]> {
  return this.http.get('assets/teams.json')
    .map(teams => teams.map(value => this.mapTeam(value.json())))
}

private mapTeam(res: any): Team {
  const teamName = Object.keys(res)[0]
  return new Team(
      teamName, 
      {away: res[teamName].form.away, home: res[teamName].form.home}, 
      res[teamName].stadium
  )
}

Your Team class can be like this:

export class Team {

  constructor(public name: string, 
              public form: { away: number, home: number }, 
              public stadium: string) { 
  }

}

It's not the subject of your question but in this the Team class it's preferable to have private properties and have getter to access it.

In your component.ts:

Just call your service and assign the value of the subscribe: this.teamService.getJSON().subscribe(value => this.teams = value)

There are antother way to do this part but it's not your question too

And finally your html it's more readable:

<div class="container">
  <table class="table">
    <thead>
      <tr>
        <th>Team</th>
        <th>Home</th>
        <th>Away</th>
        <th>Stadium</th>
      </tr>
    </thead>
    <tbody>
      <tr *ngFor="let team of teams">
        <td>{{ team.name }} </td>
        <td>{{ team.form.home }}</td>
        <td>{{ team.form.away }}</td>
        <td>{{ team.stadium }}</td>
      </tr>
    </tbody>
  </table>
</div>

The stackblitz here: https://stackblitz.com/edit/angular-gwj6nb

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download