使用*ngFor获取对象的访问键和值

我有点困惑如何在angular2中获得一个对象的keyvalue,而使用*ngFor迭代对象。我知道角1。X有一个语法

ng-repeat="(key, value) in demo"

但是我不知道如何在angular2中做同样的事情。我也做过类似的尝试,但没有成功:

    <ul>
<li *ngFor='#key of demo'>{{key}}</li>
</ul>


demo = {
'key1': [{'key11':'value11'}, {'key12':'value12'}],
'key2': [{'key21':'value21'}, {'key22':'value22'}],
}
以下是我的尝试: # EYZ0 < / p >

我怎么能得到key1key2动态使用*ngFor?经过广泛的搜索,我发现了使用管道的想法,但我不知道如何去做。 在angar2中有任何内建的管道来做同样的事情吗?< / p >

666483 次浏览
您可以创建一个自定义管道来返回每个元素的键列表。 像这样:

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;
}
}

像这样使用它:

<tr *ngFor="let c of content">
<td *ngFor="let key of c | keys">\{\{key}}: \{\{c[key]}}</td>
</tr>

编辑

你也可以返回一个包含键和值的条目:

@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;
}
}

像这样使用它:

<span *ngFor="let entry of content | keys">
Key: \{\{entry.key}}, value: \{\{entry.value}}
</span>

举例阐述@Thierry的回答。

没有内置的管道或方法可以从*ngFor循环中获取key and value。因此我们必须为相同的对象创建自定义管道。就像thierry说的,这是代码的答案。

管道类实现了PipeTransform接口的transform方法,该方法接受一个输入值和一个可选的参数字符串数组,并返回转换后的值。

transform方法对于管道来说是必不可少的。PipeTransform接口定义了该方法,并指导工具和编译器。它是可选的;不管怎样,Angular都会寻找并执行transform方法。 有关管道请参考这里

的更多信息
import {Component, Pipe, PipeTransform} from 'angular2/core';
import {CORE_DIRECTIVES, NgClass, FORM_DIRECTIVES, Control, ControlGroup, FormBuilder, Validators} from 'angular2/common';


@Component({
selector: 'my-app',
templateUrl: 'mytemplate.html',
directives: [CORE_DIRECTIVES, FORM_DIRECTIVES],
pipes: [KeysPipe]
})
export class AppComponent {


demo = {
'key1': 'ANGULAR 2',
'key2': 'Pardeep',
'key3': 'Jain',
}
}




@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;
}
}

HTML部分为:

<ul>
<li *ngFor='#key of demo | keys'>
Key: \{\{key.key}}, value: \{\{key.value}}
</li>
</ul>

工作中的Plnkr http://plnkr.co/edit/50LlK0k6OnMnkc2kNHM2?p=preview

更新RC

正如user6123723(谢谢)在评论中的建议,这里是更新。

<ul>
<li *ngFor='let key of demo | keys'>
Key: \{\{key.key}}, value: \{\{key.value}}
</li>
</ul>

谢谢管道,但我必须做一些改变之前,我可以在angular 2 RC5使用它。更改了管道导入行,并在键数组初始化中添加了any类型。

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


@Pipe({name: 'keys'})
export class KeysPipe implements PipeTransform {
transform(value) {
let keys:any = [];
for (let key in value) {
keys.push( {key: key, value: value[key]} );
}
return keys;
}
}

这里有一个简单的解决方案

你可以为此使用typescript迭代器

import {Component} from 'angular2/core';
declare var Symbol;
@Component({
selector: 'my-app',
template:`<div>
<h4>Iterating an Object using Typescript Symbol</h4><br>
Object is : <p>\{\{obj | json}}</p>
</div>
============================<br>
Iterated object params are:
<div *ngFor="#o of obj">
\{\{o}}
</div>


`
})
export class AppComponent {
public obj: any = {
"type1": ["A1", "A2", "A3","A4"],
"type2": ["B1"],
"type3": ["C1"],
"type4": ["D1","D2"]
};


constructor() {
this.obj[Symbol.iterator] =  () => {
let i =0;


return {
next: () => {
i++;
return {
done: i > 4?true:false,
value: this.obj['type'+i]
}
}
}
};
}
}

< a href = " http://plnkr.co/edit/GpmX8g?p = info”rel =“nofollow”> http://plnkr.co/edit/GpmX8g?p = info < / >

@Marton有一个对公认答案的重要异议,因为管道在每次更改检测时都会创建一个新的集合。相反,我将创建一个HtmlService,它提供了一系列实用函数,视图可以使用如下:

@Component({
selector: 'app-myview',
template: `<div *ngFor="let i of html.keys(items)">\{\{i + ' : ' + items[i]}}</div>`
})
export class MyComponent {
items = {keyOne: 'value 1', keyTwo: 'value 2', keyThree: 'value 3'};
constructor(private html: HtmlService){}
}


@Injectable()
export class HtmlService {
keys(object: {}) {
return Object.keys(object);
}
// ... other useful methods not available inside html, like isObject(), isArray(), findInArray(), and others...
}

如果你已经在使用Lodash,你可以使用这个简单的方法,包括键和值:

<ul>
<li *ngFor='let key of _.keys(demo)'>\{\{key}}: \{\{demo[key]}}</li>
</ul>

在typescript文件中,包括:

import * as _ from 'lodash';

在导出的组件中,包括:

_: any = _;

你现在必须这样做,我知道不是很有效的,因为你不想转换你从firebase接收的对象。

    this.af.database.list('/data/' + this.base64Email).subscribe(years => {
years.forEach(year => {


var localYears = [];


Object.keys(year).forEach(month => {
localYears.push(year[month])
});


year.months = localYears;


})


this.years = years;


});

在模板中有Object.keys可访问,并在*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(){}
}

我认为是客体。钥匙是这个问题的最佳解决方案。对于任何遇到这个答案并试图找出为什么Object的人。Keys给他们['0','1']而不是['key1', 'key2'],这是一个警示性的故事-注意“of”和“in”之间的区别:

我已经在使用Object了。键,类似于这个:

interface demo {
key: string;
value: string;
}


createDemo(mydemo: any): Array<demo> {
const tempdemo: Array<demo> = [];


// Caution: use "of" and not "in"
for (const key of Object.keys(mydemo)) {
tempdemo.push(
{ key: key, value: mydemo[key]}
);
}


return tempdemo;
}

然而,与其

for (const key OF Object.keys(mydemo)) {

我无意中写了

for (const key IN Object.keys(mydemo)) {

哪个“工作”完全正常,没有任何错误并返回

[{key: '0', value: undefined}, {key: '1', value: undefined}]

这花了我2个小时在谷歌上搜索和咒骂。

(打了额头上)

这里没有一个答案对我有用,下面是对我有用的:

创建pipes/keys.ts的内容:

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


@Pipe({name: 'keys'})
export class KeysPipe implements PipeTransform
{
transform(value:any, args:string[]): any {
let keys:any[] = [];
for (let key in value) {
keys.push({key: key, value: value[key]});
}
return keys;
}
}

添加到app.module.ts(你的主模块):

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

然后向模块声明数组中添加如下内容:

@NgModule({
declarations: [
KeysPipe
]
})
export class AppModule {}

然后在你的视图模板中,你可以使用这样的东西:

<option *ngFor="let entry of (myData | keys)" value="\{\{ entry.key }}">\{\{ entry.value }}</option>

在这里是我发现的一个很好的参考,如果你想阅读更多。

在其他优秀的管道中,有一个非常好的库可以做到这一点。它叫做ngx-pipes

例如,keys管道返回对象的键,values管道返回对象的值:

钥匙管

<div *ngFor="let key of {foo: 1, bar: 2} | keys">\{\{key}}</div>
<!-- Output: 'foo' and 'bar -->

价值管

<div *ngFor="let value of {foo: 1, bar: 2} | values">\{\{value}}</div>
<!-- Output: 1 and 2 -->

不需要创建自己的自定义管道:)

更新

6.1.0-beta.1 KeyValuePipe中引入了https://github.com/angular/angular/pull/24319

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

< a href = " https://plnkr.co/edit/eIfgvtsd66ztkDN2Xzio?p=preview" rel="noreferrer">活塞示例 . p=preview" rel="noreferrer">活塞示例

之前的版本

另一种方法是创建NgForIn指令,它将像这样使用:

<div *ngFor="let key in obj">
<b>\{\{ key }}</b>: \{\{ obj[key] }}
</div>

< a href = " https://plnkr.co/edit/6tDTIfl14chTOJfEzKbr?p=preview" rel="noreferrer">活塞示例 . p=preview" rel="noreferrer">活塞示例

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);
}
}
}

更改演示类型为数组 或者迭代你的对象并推到另一个数组

public details =[];
Object.keys(demo).forEach(key => {
this.details.push({"key":key,"value":demo[key]);
});

从html:

<div *ngFor="obj of details">
<p>\{\{obj.key}}</p>
<p>\{\{obj.value}}</p>
<p></p>
</div>
Angular的最新版本(v6.1.0)一样,Angular团队为keyvalue管道添加了新的内建管道,以帮助你迭代Angular包的common模块中的对象、映射和数组。 例如-

<div *ngFor="let item of testObject | keyvalue">
Key: <b>\{\{item.key}}</b> and Value: <b>\{\{item.value}}</b>
</div>

保持原来的顺序,使用keyvalue:onCompare
在组件中定义callback:

// ...
import {KeyValue} from '@angular/common';


@Component(/* ... */)
export class MyComponent {
private onCompare(_left: KeyValue<any, any>, _right: KeyValue<any, any>): number {
return -1;
}
}

Working fork Example . bref ="https://stackblitz.com/edit/angular6-keyvaluepipe-demo?file=src%2Fapp%2Fapp.component.ts" rel="noreferrer">Working fork示例

点击这里查看更多有用的信息

如果你使用的是Angular v5或更低版本,或者你想使用管道实现,请遵循这个答案

在Angular 6.1中,你可以使用keyvalue管道:

<div *ngFor="let item of testObject | keyvalue">
Key: <b>\{\{item.key}}</b> and Value: <b>\{\{item.value}}</b>
</div>
但是它有一个不方便的地方,就是根据键值对结果列表进行排序。 如果你需要一些中性的东西:

@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;
}
}

不要忘记指定纯:假管道属性。在这种情况下,管道在每个更改检测周期中都被调用,即使输入引用没有更改(向对象添加属性时也是如此)。

你可以通过尝试得到动态对象的键

myObj['key']

使用指数:

<div *ngFor="let value of Objects; index as key">

用法:

\{\{key}} -> \{\{value}}

我想为Angular 8添加一个答案:

对于循环,你可以做:

<ng-container *ngFor="let item of BATCH_FILE_HEADERS | keyvalue: keepOriginalOrder">
<th nxHeaderCell>\{\{'upload.bulk.headings.'+item.key |translate}}</th>
</ng-container>

同样,如果你需要上面的数组来保持原始的顺序,那么在你的类中声明这个:

public keepOriginalOrder = (a, b) => a.key;

像这样创建数组

tags = [
{
name : 'Aliko Dogara',
amount   : '60,000',
purpose: 'Office repairs'
},
{
name : 'Aliko Dogara',
amount   : '60,000',
purpose: 'Office repairs'
},
{
name : 'Aliko Dogara',
amount   : '60,000',
purpose: 'Office repairs'
},
{
name : 'Aliko Dogara',
amount   : '60,000',
purpose: 'Office repairs'
},
{
name : 'Aliko Dogara',
amount   : '60,000',
purpose: 'Office repairs'
}
];

一直都有效

你可以使用keyvalue管道作为示例代码提供:

    <div style="flex-direction: column">
<app-cart-item
class="cart-item"
*ngFor="let keyValuePair of this.allProductRecords | keyvalue"
[productRecord]="keyValuePair.value"
(removeProduct)="removeProductFromCart(keyValuePair.key)"
></app-cart-item>
<br />
<p style="font-family: Verdana, Geneva, Tahoma, sans-serif; font-weight: bolder">
Total $\{\{ getTotalPurchaseAmount() }}
</p>
</div>

ECMA 2017+解决方案

遵循一些其他答案的思想,您可以创建一个到从你的对象中创建一个[key, value]数组的管道,但是以一种更简单的方式,遵循在ECMA 2017中引入的新方法Object.entries

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


/**
* Transform a literal object into array
*/
@Pipe({
name: 'forObject',
pure: true,
})
export class ForObjectPipe implements PipeTransform {


transform(object, args?: any): any {
return Object.entries(object);
}
}

模块

在模块中,声明并提供它

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';


import { ForObjectPipe } from './for-object.pipe';


import { MyPageRoutingModule } from './my-routing.module';
import { MyPage } from './my.page';


@NgModule({
imports: [
CommonModule,
MyPageRoutingModule,
],
declarations: [
MyPage,
ForObjectPipe,
],
providers: [
ForObjectPipe,
]
})
export class MyPageModule {}

然后你可以在你的组件中使用typescript代码或HTML。

组件中使用

// ...
import { ForObjectPipe } from './for-object.pipe';


@Component({
selector: 'app-my',
templateUrl: './my.page.html',
styleUrls: ['./my.page.scss'],
})
export class MyComponent {
obj: { [key: any]: any } = {
1: 'hello',
2: 'world',
};


constructor(private forObjectPipe: ForObjectPipe) { }


foo() {
const myArray = this.forObjectPipe.transform(this.obj);
// same as
const myArray = Object.entries(this.obj);
}
}

在组件视图中使用

<h1>Object:</h1>
<div *ngFor="let pair of obj | forObject">
KEY: \{\{ pair[0] }} - VALUE: \{\{ pair[1] }}
</div>

输出:

Object:
KEY: 1 - VALUE: hello
KEY: 2 - VALUE: world

现场演示:https://stackblitz.com/edit/angular-qapapx?file=src/app/hello.component.ts