1

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.

4
  • 1
    If you have control over the API, I'd suggest changing the structure. That structure looks really odd: keys should be known values, not the payload data. Commented Nov 24, 2017 at 19:16
  • @IngoBürk what would you suggest I change it to? Commented Nov 24, 2017 at 22:27
  • 1
    It should be something like { name: "Arsenal", form: {...}, ... }. That way you can just iterate over the array directly and the awkwardness goes away. You can use the HTML in @mickaelw's answer, just without needing to go through mapping it to a class. Commented Nov 25, 2017 at 6:28
  • 1
    @IngoBürk alright, cheers. I simply changed my Python code to make it like that, and it's much easier like you said! Commented Nov 25, 2017 at 14:53

1 Answer 1

2

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(team => this.mapTeam(team)))
}

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

Sign up to request clarification or add additional context in comments.

5 Comments

@Esoemah can you retry it? I just use Observable.of(...) instead of http.get to simulate the json file
I get the following error when using http.get: Property 'map' does not exist on type 'Response'..
@Esoemah I check that I have a 403 on stackblitz with the json
What? Try doing it with http.get instead of Observable.of, it doesn't work.
Alright I managed to get it working by changing value.json() to just value amongst some other things, so thanks a lot.

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.