access key and value of object using *ngFor
As in latest release of Angular (v6.1.0) , Angular Team has added new built in pipe for the same named as keyvalue
pipe to help you iterate through objects, maps, and arrays, in the common
module of angular package.
For example -
<div *ngFor="let item of testObject | keyvalue">
Key: <b>{{item.key}}</b> and Value: <b>{{item.value}}</b>
</div>
To keep original order, use keyvalue:onCompare
,
and in component define callback:
// ...
import {KeyValue} from '@angular/common';
@Component(/* ... */)
export class MyComponent {
private onCompare(_left: KeyValue<any, any>, _right: KeyValue<any, any>): number {
return -1;
}
}
Working Forked Example
check it out here for more useful information -
- https://github.com/angular/angular/blob/master/CHANGELOG.md#features-3
- https://github.com/angular/angular/commit/2b49bf7
If you are using Angular v5 or below or you want to achieve using pipe follow this answer
- access key and value of object using ngfor
Have Object.keys
accessible in the template and use it in *ngFor
.
@Component({
selector: 'app-myview',
template: `<div *ngFor="let key of objectKeys(items)">{{key + ' : ' + items[key]}}</div>`
})
export class MyComponent {
objectKeys = Object.keys;
items = { keyOne: 'value 1', keyTwo: 'value 2', keyThree: 'value 3' };
constructor(){}
}
You could create a custom pipe to return the list of key for each element. Something like that:
import { PipeTransform, Pipe } from '@angular/core';
@Pipe({name: 'keys'})
export class KeysPipe implements PipeTransform {
transform(value, args:string[]) : any {
let keys = [];
for (let key in value) {
keys.push(key);
}
return keys;
}
}
and use it like that:
<tr *ngFor="let c of content">
<td *ngFor="let key of c | keys">{{key}}: {{c[key]}}</td>
</tr>
Edit
You could also return an entry containing both key and value:
@Pipe({name: 'keys'})
export class KeysPipe implements PipeTransform {
transform(value, args:string[]) : any {
let keys = [];
for (let key in value) {
keys.push({key: key, value: value[key]});
}
return keys;
}
}
and use it like that:
<span *ngFor="let entry of content | keys">
Key: {{entry.key}}, value: {{entry.value}}
</span>
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
Another approach is to create NgForIn
directive that will be used like:
<div *ngFor="let key in obj">
<b>{{ key }}</b>: {{ obj[key] }}
</div>
Plunker Example
ngforin.directive.ts
@Directive({
selector: '[ngFor][ngForIn]'
})
export class NgForIn<T> extends NgForOf<T> implements OnChanges {
@Input() ngForIn: any;
ngOnChanges(changes: NgForInChanges): void {
if (changes.ngForIn) {
this.ngForOf = Object.keys(this.ngForIn) as Array<any>;
const change = changes.ngForIn;
const currentValue = Object.keys(change.currentValue);
const previousValue = change.previousValue ? Object.keys(change.previousValue) : undefined;
changes.ngForOf = new SimpleChange(previousValue, currentValue, change.firstChange);
super.ngOnChanges(changes);
}
}
}
From Angular 6.1 you can use the keyvalue pipe:
<div *ngFor="let item of testObject | keyvalue">
Key: <b>{{item.key}}</b> and Value: <b>{{item.value}}</b>
</div>
But it has the inconvenient that sorts the resulting list by the key value. If you need something neutral:
@Pipe({ name: 'keyValueUnsorted', pure: false })
export class KeyValuePipe implements PipeTransform {
transform(input: any): any {
let keys = [];
for (let key in input) {
if (input.hasOwnProperty(key)) {
keys.push({ key: key, value: input[key]});
}
}
return keys;
}
}
Don't forget to specify the pure:false pipe attribute. In this case, the pipe is invoked on each change-detection cycle, even if the input reference has not changed (so is the case when you add properties to an object).