How to iterate object keys using *ngFor?

31,203

Solution 1

Update

In 6.1.0-beta.1 KeyValuePipe was introduced https://github.com/angular/angular/pull/24319

<div *ngFor="let item of {'b': 1, 'a': 1} | keyvalue">
  {{ item.key }} - {{ item.value }}
</div>

Plunker Example

Previous version

You could try something like this

export class ObjNgFor implements PipeTransform {
    transform(value: any, args: any[] = null): any {
        return Object.keys(value).map(key => Object.assign({ key }, value[key]));
    }
}

And then on your template

  <div *ngFor="let obj of objs | ObjNgFor">
   {{obj.key}} - {{obj.description}}
  </div>

Plunker

Solution 2

Or instead of creating a pipe and passing an object to *ngFor, just pass Object.keys(MyObject) to *ngFor. It returns the same as the pipe, but without the hassle.

On TypeScript file:

let list = Object.keys(MyObject); // good old javascript on the rescue

On template (html):

*ngFor="let item of list"

Solution 3

Just return the keys from the pipe instead of the values and then use the keys to access the values:

(let instead of # in the beta.17)

@Pipe({ name: 'ObjNgFor',  pure: false })
export class ObjNgFor implements PipeTransform {
    transform(value: any, args: any[] = null): any {
        return Object.keys(value)//.map(key => value[key]);
    }
}
@Component({
    selector: 'my-app',
    pipes: [ObjNgFor],
    template: `
    <h1>Hello</h1>
 <div *ngFor="let key of objs | ObjNgFor">{{key}}:{{objs[key].description}}</div>    `,
})
export class AppComponent {
  objs = {
    "propertyA":{
      "description":"this is the propertyA",
      "default":"sth"
    },
    "propertyB":{
      "description":"this is the propertyB",
      "default":"sth"
    }
  };
}

Plunker example

See also Select based on enum in Angular2

Solution 4

keys.pipe.ts

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({ name: 'keys' })
export class KeysPipe implements PipeTransform {
    transform(obj: Object, args: any[] = null): any {
        let array = [];
        Object.keys(obj).forEach(key => {
            array.push({
                value: obj[key],
                key: key
            });
        });
        return array;
    }
}

app.module.ts

import { KeysPipe } from './keys.pipe';

@NgModule({
  declarations: [
    ...
    KeysPipe
  ]
})

example.component.html

<elem *ngFor="let item of obj | keys" id="{{ item.key }}">
    {{ item.value }}
</elem>
Share:
31,203
uksz
Author by

uksz

Newbie

Updated on December 19, 2020

Comments

  • uksz
    uksz over 3 years

    I've been digging around, and found out that I can use the following to use *ngFor over an object:

     <div *ngFor="#obj of objs | ObjNgFor">...</div>
    

    where ObjNgFor pipe is:

    @Pipe({ name: 'ObjNgFor',  pure: false })
    export class ObjNgFor implements PipeTransform {
        transform(value: any, args: any[] = null): any {
            return Object.keys(value).map(key => value[key]);
        }
    }
    

    However, when I have an object like this:

    {
    "propertyA":{
        "description":"this is the propertyA",
        "default":"sth"
     },
    "propertyB":{
        "description":"this is the propertyB",
        "default":"sth"
     }
    }
    

    I am not quite sure how I can extract 'propertyA' and 'propertyB', so that it is accessible from the *ngFor directive. Any ideas?

    UPDATE

    What I want to do, is to present the following HTML:

            <div *ngFor="#obj of objs | ObjNgFor" class="parameters-container">
                <div class="parameter-desc">
                    {{SOMETHING}}:{{obj.description}}
                </div>
            </div>
    

    Where something would be equal to propertyA and propertyB (this is how the object is structured). So, this would lead to:

    propertyA:this is the propertyA
    propertyB:this is the propertyB
    
  • uksz
    uksz almost 8 years
    Gunter - I would like to show user either 'propertyA' or 'propertyB'. So I need to change the pipe somehow
  • Günter Zöchbauer
    Günter Zöchbauer almost 8 years
    Not sure what you mean by that. Depending no what criteria do you want to show one or the other?
  • Günter Zöchbauer
    Günter Zöchbauer almost 8 years
    Not sure what exact use case you have in mind but I don't see why anything would not work with nested objects.
  • sabithpocker
    sabithpocker almost 7 years
    Can this be coupled with async pipe if objs is asynchronous?
  • Günter Zöchbauer
    Günter Zöchbauer almost 7 years
    Sure {{someObservable | async | ObjNgFor}}
  • leotesta
    leotesta over 6 years
    @GünterZöchbauer how I can access to object value in asynchronous case with this approach ?
  • Gaspa79
    Gaspa79 almost 6 years
    Thank you!!! This made it look simple. You should add what to put on the template part btw =)
  • Willem de Jong
    Willem de Jong almost 6 years
    neat solution. I got the number values and the string values in the list though so I used the slice method to get the proper side of the array: options.slice(options.length / 2). Found this solution here: stackoverflow.com/questions/38554562/…
  • ideeps
    ideeps over 5 years
    The key value pipe is sorting out by the order of the keys and values orders in angular 6. How can we disable that ?
  • zmag
    zmag over 4 years
    Complete code would be helpful instead of part of it.