我对在使用 *ngFor
迭代对象时如何在 angular2 中获取对象的 key
和 value
感到有些困惑。我知道在 Angular 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'}],
}
这是我尝试的 plnkr:http://plnkr.co/edit/mIj619FncOpfdwrR0KeG?p=preview
如何使用 *ngFor
动态获取 key1
和 key2
?经过广泛搜索,我发现了使用管道的想法,但我不知道如何去做。在angular2中是否有任何内置管道可以做同样的事情?
Pipe
..
与 Angular 的最新版本 (v6.1.0) 一样,Angular 团队为与 keyvalue
管道相同的名称添加了新的内置管道,以帮助您在common
角度包模块。例如 -
<div *ngFor="let item of testObject | keyvalue">
Key: <b>{{item.key}}</b> and Value: <b>{{item.value}}</b>
</div>
要保持原始顺序,请使用 keyvalue:onCompare
,
并在组件中定义回调:
// ...
import {KeyValue} from '@angular/common';
@Component(/* ... */)
export class MyComponent {
private onCompare(_left: KeyValue<any, any>, _right: KeyValue<any, any>): number {
return -1;
}
}
工作分叉示例
在这里查看更多有用的信息 -
https://github.com/angular/angular/blob/master/CHANGELOG.md#features-3
https://github.com/angular/angular/commit/2b49bf7
如果您使用的是 Angular v5 或更低版本,或者您想使用管道实现,请遵循此答案
使用 ngfor 访问对象的键和值
在模板中访问 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(){}
}
*ngFor
。前两个使用 objectKeys
,最里面不需要(因为它只是一个数组)。
您可以创建一个自定义管道来返回每个元素的键列表。像这样的东西:
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>
keys.push({key: key, value: value[key]);
中缺少的右括号
*ngFor
表达式中创建集合。它造成了巨大的性能瓶颈,因为它需要在每次更改检测器检查更改时生成集合。
pure:false
添加到管道,它会变得非常低效。每当我更改对象(删除项目)时,您是否有手动更新管道的解决方案?
common: NgFor has been removed as it was deprecated since v4. Use NgForOf instead. This does not impact the use of*ngFor in your templates.
(jaxenter.com/road-to-angular-5-133253.html)
更新
在 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>
以前的版本
另一种方法是创建 NgForIn
指令,其用法如下:
<div *ngFor="let key in obj">
<b>{{ key }}</b>: {{ obj[key] }}
</div>
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);
}
}
}
从 Angular 6.1 开始,您可以使用键值管道:
<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;
}
}
不要忘记指定 pure:false 管道属性。在这种情况下,管道会在每个更改检测周期中调用,即使输入引用没有更改(向对象添加属性时也是如此)。
举例说明@Thierry 的答案。
没有内置管道或方法可以从 *ngFor 循环中获取 key and value
。所以我们必须为此创建自定义管道。正如蒂埃里所说,这里是代码的答案。
** 管道类实现了 PipeTransform 接口的 transform 方法,该方法接受一个输入值和一个可选的参数字符串数组并返回转换后的值。
** transform 方法对于管道是必不可少的。 PipeTransform 接口定义该方法并指导工具和编译器。它是可选的;不管怎样,Angular 都会寻找并执行 transform 方法。有关管道 refer here 的更多信息
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
正如用户6123723(谢谢)在评论中所建议的,这里是更新。
<ul>
<li *ngFor='let key of demo | keys'>
Key: {{key.key}}, value: {{key.value}}
</li>
</ul>
@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...
}
Object.keys(...)
有什么好处?
TypeError: Cannot read property 'keys' of undefined
。模板中似乎不支持它。
template
选项中使用,而是在模板的实际 html 代码中使用吗?谢谢
如果你已经在使用 Lodash,你可以使用这个包含键和值的简单方法:
<ul>
<li *ngFor='let key of _.keys(demo)'>{{key}}: {{demo[key]}}</li>
</ul>
在打字稿文件中,包括:
import * as _ from 'lodash';
在导出的组件中,包括:
_: any = _;
考虑为 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;
感谢管道,但我必须先进行一些更改,然后才能在 angular 2 RC5 中使用它。更改了管道导入行,并将任何类型添加到键数组初始化中。
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;
}
}
这里没有一个答案对我有用,这对我有用:
使用以下内容创建 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>
如果您想了解更多信息,我发现 Here 是一个很好的参考。
#
等语法。顺便说一句,你的答案无疑也是正确的
使用指数:
<div *ngFor="let value of Objects; index as key">
用法:
{{key}} -> {{value}}
您可以使用 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>
在其他不错的管道中,有一个非常好的库可以做到这一点。它称为 ngx-pipes。
例如,keys 管道返回对象的键,值管道返回对象的值:
键管
<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 -->
无需创建自己的自定义管道 :)
这是简单的解决方案
您可以为此使用打字稿迭代器
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]
}
}
}
};
}
}
http://plnkr.co/edit/GpmX8g?p=info
将演示类型更改为数组或迭代您的对象并推送到另一个数组
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>
我认为 Object.keys 是解决这个问题的最佳方法。对于遇到此答案并试图找出为什么 Object.keys 给他们 ['0', '1'] 而不是 ['key1', 'key2'] 的任何人,这是一个警示故事 - 请注意“的”和“在”:
我已经在使用 Object.keys,类似于以下内容:
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 个小时的谷歌搜索和诅咒..
(拍了拍额头)
你现在必须这样做,我知道效率不是很高,因为你不想转换从 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;
});
您可以通过尝试获得动态对象的密钥
myObj['key']
ECMA 2017+ 解决方案
按照其他一些答案的想法,您可以创建一个管道来从您的对象创建一个 [key, value]
数组,但是以更简单的方式,遵循 Object.entries
中引入的新方法 Object.entries
2}。
管道
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 {}
然后你可以在你的组件中使用打字稿代码或 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
Object.entries
而不是使用 Object.values
。感谢您指出了这一点。
像这样创建你的数组
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'
}
];
一直在工作
*ngFor="let item of testObject | keyvalue:keepOriginalOrder"
并在您的类中定义:public keepOriginalOrder = (a, b) => a.key