Search code examples
javascripttypescriptobjectinterfaceangular7

Typescript / Angular 7: How can I iterate over Object matching my Interface with Object.keys?


I am pretty new to Javascript and Typescript/Angular..

I am getting data / game stats from a website to make my own stats app. I have created an Interface with defined Key/Values to match the data that I want to show on my template.

The API's response that I wish to show is in the form of nested objects. Because of this, I am using Object.keys() in order to iterate through the objects, and show the result on my HTML template.

I am able to show JSON of the specific nested Object just fine. My problem is: it is showing the ENTIRE Key/Values of that Object, and not the specific key values I have defined in my Interface.

Within my HTML, I am looping through my Interface called lifeTimeStat Object.keys(lifeTimeStat) - (also please see below for full html)

Seeing as how I need to iterate through an Object, I attempted to make my lifeTimeStat Interface an object.. Like this:

`export class CombatListComponent implements OnInit {

constructor(public combatService: CombatService) { }

lifeTimeStats: lifeTimeStat = {
headshotKills: null,
             kills: null,
             longestKill: null, 
             maxKillStreaks: null,
             dailyKills: null,
             weeklyKills: null,
             damageDealt: null,
             roadKills: null,
             teamKills: null,
              vehicleDestroys: null,
              suicides: null,
              roundMostKills: null,
              dBNOs: null,
              assists: null
  } 


ngOnInit() {
this.combatService.getCombat().subscribe(data => {this.lifeTimeStats = 
data} );  
}
}

`

But of course, however, I am getting this error: TypeError: Cannot read property 'keys' of undefined .. So it seems I am not making my Interface into an Object the right way..

The only way that I can get the JSON to show in my HTML is if I instead define Object = Object instead of that crappy attempt of turning my Interface into an object.. Argh. Object = Object will just show the entire Object and not the specific shape of my Interface..

HTML: combat-list.component.html <div *ngFor="let key of Object.keys(lifeTimeStat)"> {{ lifeTimeStats[key].attributes.gameModeStats.solo| json }} </div> <br>

Service Component: combat.service.ts

`@Injectable({
  providedIn: 'root'
})
export class CombatService {
getCombat():Observable<lifeTimeStat> {

return this.http.get<lifeTimeStat>(this.configUrl,  { observe:'body',   
responseType: 'json', headers: getHeaders });    

}`

Interface:

    `export interface lifeTimeStat {


            headshotKills: number,
             kills: number,
             longestKill: number, 
             maxKillStreaks: number,
             dailyKills: number,
             weeklyKills: number,
             damageDealt: number,
             roadKills: number,
             teamKills: number,
              vehicleDestroys: number,
              suicides: number,
              roundMostKills: number,
              dBNOs: number,
              assists: number,



}  `

I just want to show the selected data as I have defined in my Interface. I've been googling / searching on SO for many hours over the course of two, almost three days :(


Solution

  • So this syntax should work:

    Object
      .keys({ a: 1, b: 2 })
      .map(key => console.log(key));
    

    If not, why don't you assign the array to a variable and iterate over the variable?

    In any case, you can use this nice helper to preserve types and iterate over both keys and values:

    const testObject = {
      completed: true,
      score: 129.1,
      description: 'none',
    };
    
    entries(testObject)
     .map(([key, value]) => console.log(`Key is ${key}, value is ${value}`));
    
    function entries<K>(object: K)  {
        return (Object.keys(object) as (keyof K)[])
            .filter((key) => object[key] !== undefined && object[key] !== null)
            .map(
                key => ([
                    key,
                    object[key],
                ] as [keyof K, Required<K>[keyof K]]),
        );
    }
    
    type Required<T> = {
        [P in keyof T]-?: T[P];
    };
    

    Or for your case:

    const keyValuePairs = entries(lifeTimeStat);
    
    ...
    
    <div *ngFor="const [key, value] of keyValuePairs">    {{ value.attributes.gameModeStats.solo| json }}  </div> <br>