如何循环对象属性与 ngFor 在角度

这篇文章是关于我在工作中发现的一个有趣的问题。

如果你还不知道,我说的是角度2 +

问题是

所以你想要显示一个列表的标记这个列表的值来自后端出于某种原因而不是传统的对象数组你会收到类似这样的东西。

    {
"car" :
{
"color" : "red",
"model" : "2013"
},
"motorcycle":
{
"color" : "red",
"model" : "2016"
},
"bicycle":
{
"color" : "red",
"model" : "2011"
}
}

然后尝试使用 * ngFor,但出现了一个错误消息:

Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.

你可以在后端修复它,这样你就得到了一个对象数组,但是没有人有时间做这个。别担心,孩子,有我呢。

115304 次浏览

The solution

In a perfect world, you would get an array of objects, since the world is not always, perfect. What you want to do, is to store all those objects within an array. Here is an over-simplified solution in plain old JavaScript.

Step 1. Get all the object keys. using Object.keys. This method returns an array of a given object’s own enumerable properties.

Step 2. Create an empty array. This is an where all the properties are going to live, since your new ngFor loop is going to point to this array, we gotta catch them all.

Step 3. Iterate throw all keys, and push each one into the array you created.

Here’s how that looks like in code.

// Evil response in a variable. Here are all my vehicles.
let evilResponse = {
"car" :
{
"color" : "red",
"model" : "2013"
},
"motorcycle":
{
"color" : "red",
"model" : "2016"
},
"bicycle":
{
"color" : "red",
"model" : "2011"
}
}
// Step 1. Get all the object keys.
let evilResponseProps = Object.keys(evilResponse);
// Step 2. Create an empty array.
let goodResponse = [];
// Step 3. Iterate throw all keys.
for (prop of evilResponseProps) {
goodResponse.push(evilResponseProps[prop]);
}

Then you can assign the goodResponse to the class property you were trying to iterare trough in the first place.

That’s all folks.

A better solution would be to use a pipe such as this one:

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


/**
* Convert Object to array of keys.
*/
@Pipe({
name: 'appProperties'
})
export class PropertiesPipe implements PipeTransform {


transform(value: {}): string[] {


if (!value) {
return [];
}


return Object.keys(value);
}
}

Then in your template:

<div *ngFor="let property of response | appProperties">
<div *ngFor="let item of response[property]">
\{\{item.something}}
</div>
</div>

I don't know if this is safe, but for these simple cases i don't like the pipe solution, so i usually use:

<div *ngFor="let k of objectKeys(yourObject)">
\{\{yourObject[k].color}}
</div>

and in the controller:

objectKeys(obj) {
return Object.keys(obj);
}

This is a quite frequent case, i don't understand why there isn't a standard implementation for this like in Angular.js 1.x

In Angular 6.1 the KeyValuePipe was introduced which allows you to iterate object properties:

<div *ngFor="let item of object | keyvalue">
\{\{item.key}}:\{\{item.value}}
</div>

Docs: https://angular.io/api/common/KeyValuePipe

    <div *ngFor="let item of donation_list | keyvalue">
<div class="donation-box">
<Label class="donation-label">Date : \{\{item.value.PaymentDate}}</Label>
<Label class="donation-label">Time : \{\{item.value.PaymentTime}}</Label>


</div>
</div>

If you have more properties inside the object, you can use like this.

Use Object.values to get a regular array from your object. Object.keys seems like a lot of unnecessary work.

Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Object/values

You can try this:

<div *ngFor="let item of object | keyvalue">
\{\{item.key}}:\{\{item.value}}
</div>

For more info visit: https://angular.io/api/common/KeyValuePipe

declare your array as any and then assign your object

data=[] as any;
myObj={};


data=myObj;

now loop through data array

<tr *ngFor="let item of data">
<td>\{\{item.property}}</td>
</tr>