-1

I know similar questions were asked several times before, but couldn't find my answer there. I would like to iterate through an 'interface' array as you can see in the HTML part.

Angular component:

export class PlayerComponent {

  constructor(private playerApiService: PlayerApiService) {}

  ngOnInit(): void {
    this.getPlayers();
  }

  objectKeys = Object.keys;  

  players: IPlayer[] = [];
  
  getPlayers(): void {
    this.playerApiService.getPlayers().subscribe(players => {
      this.players = players;
    });
  }
}

Angular HTML:

<div *ngFor="let key of objectKeys(players)">
    Key: {{key}}

    <div *ngFor="let player of players[key]">
        {{player.name}}
        {{player.isAttending}}
    </div>
</div>

JSON:

{
  "player": [
    {
      "id": 1,
      "name": "Andrew",
      "isAttending": false
    },
    {
      "id": 2,
      "name": "Blair",
      "isAttending": true
    },
    {
      "id": 3,
      "name": "Carl",
      "isAttending": true
    },
    {
      "id": 4,
      "name": "Diane",
      "isAttending": false
    }
  ]
}

Angular interface:

export interface IPlayer {
    id: number,
    name: string,
    isAttending: boolean
}

It works without the interface, but how it is done by using the interface?

//players: IPlayer[] = [];
players: { [key: string]: any } = [];
Tomo
  • 429
  • 1
  • 10
  • 24

2 Answers2

0

The type of your JSON is

interface Players{
   player: IPlayer[]
}

// or type Players = Record<string,IPlayer[]>

So you should have:

players: Players = {player:[]};

To sumup:

export class PlayerComponent {

  constructor(private playerApiService: PlayerApiService) {}

  ngOnInit(): void {
    this.getPlayers();
  }

  objectKeys = Object.keys;  

  players: { [key: string]: IPlayer[] } = {}
  
  getPlayers(): void {
    this.playerApiService
         .getPlayers()
         .subscribe((players:{ [key: string]: IPlayer[] }) => {
            this.players = players;
         });
  }
}


// Warning, this.playerApiService.getPlayers() should return the type { [key: string]: IPlayer[] }
Wandrille
  • 6,267
  • 3
  • 20
  • 43
  • You mean an interface inside an interface? – Tomo May 11 '23 at 15:18
  • Yes, if your JSON is right, `getPlayers()` returns `Players` which contains the `IPlayer` – Wandrille May 11 '23 at 15:20
  • Or if you want a shortcut, you can just do `players: { [key: string]: IPlayer[] } = [];` – Wandrille May 11 '23 at 15:21
  • ```players: { [key: string]: IPlayer[] } = [];``` won't work. *Type 'never[]' is not assignable to type '{ [key: string]: IPlayer[]; }'. Index signature for type 'string' is missing in type 'never[]'.* – Tomo May 12 '23 at 09:22
  • Sorry, my mistake: `players: { [key: string]: IPlayer[] } = {}` – Wandrille May 12 '23 at 09:25
  • *Type 'IPlayer[]' is not assignable to type '{ [key: string]: IPlayer[]; }'. Index signature for type 'string' is missing in type 'IPlayer[]'* in ```this.players = players;``` – Tomo May 12 '23 at 11:09
  • I have added to my answer, the full solution – Wandrille May 12 '23 at 12:54
  • I get the *No overload matches this call* error as in the comments under @don-delice solution. – Tomo May 12 '23 at 17:54
  • Please create a stackblitz example, otherwise it will be endless – Wandrille May 12 '23 at 18:46
  • https://stackblitz.com/edit/angular-3m3qqx – Tomo May 13 '23 at 16:22
  • `getPlayers(): Observable`. It's wrong. It should be just `Players` as well for `this.httpClient.get('/assets/player.json');`. It should be `this.httpClient.get('/assets/player.json');` – Wandrille May 13 '23 at 16:25
  • Something like this https://stackblitz.com/edit/angular-7ks6jv?file=src%2Fapp%2Fplayer.ts,src%2Fapp%2Fplayer-api.service.ts,src%2Fapp%2Fplayer%2Fplayer.component.ts,src%2Fapp%2Fplayer%2Fplayer.component.html,src%2Fapp%2Fapp.component.ts – Wandrille May 13 '23 at 16:29
  • Perhaps my question is misleading, but the interface must stay as it is. So, no interface inside interface - I don't know if this is good practice, but that's a question for another thread. What I would like to achieve is to iterate what I get - https://i.postimg.cc/j201QSb9/player.png . I guess I'm supposed to use objectKeys or keyvalue, but by trying to do so, I get the error mentioned in my question. – Tomo May 16 '23 at 14:11
  • But your interface is wrong. `players` is not equal to your `IPlayer[]`. In anycase, you need to change your code – Wandrille May 16 '23 at 21:17
  • Well, that works ```this.httpClient.get('/assets/player.json')``` and ```players: IPlayer[] = []``` is populated. So the question remains, how to iterate ***players***? – Tomo May 17 '23 at 08:48
  • Typescript can't know the type of `'/assets/player.json'`. So it believes your call `IPlayer[]` which is wrong. – Wandrille May 17 '23 at 09:02
  • Yeah, but that's for another thread. I just wanna know how to iterate the result. It doesn't matter if it's right or wrong. The JSON is temporary, in the end I will get data from a db. Forget how ***players*** is populated and imagine that you have it that way (and you can't change how it gets served), but you need to iterate it. – Tomo May 17 '23 at 11:27
0

It doesn't work because you have not mentioned the type on the parameter when subscribing to the observable, you can try to do like this :

  getPlayers(): void {
      this.playerApiService.getPlayers().subscribe((players:IPlayer) => {
      this.players = players;
    });
  }

This should work properly but make sure that you have imported the interface in your component. This error occurred because typescript is strict about respecting types.

I hope this helps, let me know if any further questions

Gary Bao 鲍昱彤
  • 2,608
  • 20
  • 31
  • *No overload matches this call. Overload 1 of 2, '(observerOrNext?: Partial> | ((value: IPlayer[]) => void) | undefined): Subscription', gave the following error. Argument of type '(players: IPlayer) => void' is not assignable to parameter of type 'Partial> | ((value: IPlayer[]) => void) | undefined'. Type '(players: IPlayer) => void' is not assignable to type '(value: IPlayer[]) => void'. Types of parameters 'players' and 'value' are incompatible.* – Tomo May 12 '23 at 09:36
  • * Type 'IPlayer[]' is missing the following properties from type 'IPlayer': id, name, isAttending Overload 2 of 2, '(next?: ((value: IPlayer[]) => void) | null | undefined, error?: ((error: any) => void) | null | undefined, complete?: (() => void) | null | undefined): Subscription', gave the following error. Argument of type '(players: IPlayer) => void' is not assignable to parameter of type '(value: IPlayer[]) => void'. Types of parameters 'players' and 'value' are incompatible. Type 'IPlayer[]' is not assignable to type 'IPlayer'.* – Tomo May 12 '23 at 09:36