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

时间:2016-02-21 10:28:25

标签: angular typescript object

我对使用key迭代对象时如何获取angular2中对象的value*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'}],
  }

这是我尝试的一个方面: http://plnkr.co/edit/mIj619FncOpfdwrR0KeG?p=preview

如何使用key1动态获取key2*ngFor?在广泛搜索之后,我发现了使用管道的想法,但我不知道如何去做。 是否有任何内置管道在angular2中做同样的事情?

18 个答案:

答案 0 :(得分:298)

在模板中可以访问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(){}
}

答案 1 :(得分:203)

您可以创建自定义管道以返回每个元素的键列表。 这样的事情:

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>

答案 2 :(得分:162)

最新版本的Angular(v6.1.0)一样,Angular Team为keyvalue管道添加了新的内置管道,以帮助您遍历对象,地图,和数组,位于angular包的common模块中。 例如-

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

Working Forked Example

在此处查看更多有用的信息-

如果您使用的是Angular v5或更低版本,或者您想要使用管道来实现,请遵循以下答案

答案 3 :(得分:35)

更新

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>

<强> Plunker Example

以前的版本

另一种方法是创建将使用的NgForIn指令,如:

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

答案 4 :(得分:23)

以示例的方式阐述@ Thierry的答案。

没有内置管道或方法从* ngFor循环中获取key and value。所以我们必须为它创建自定义管道。正如蒂埃里所说,这是代码的答案。

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

**转换方法对管道至关重要。 PipeTransform接口定义该方法并指导工具和编译器。它是可选的;无论如何,Angular会查找并执行转换方法。 有关管道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

正如user6123723(感谢)在评论中所建议的那样是更新。

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

答案 5 :(得分:21)

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

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

答案 6 :(得分:18)

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

答案 7 :(得分:15)

如果你已经在使用Lodash,你可以采用这种简单的方法,包括密钥和价值:

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

在打字稿文件中,包括:

import * as _ from 'lodash';

并在导出的组件中包含:

_: any = _;

答案 8 :(得分:8)

感谢管道,但我必须做一些更改才能在角度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;
  }
}

答案 9 :(得分:6)

要为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;

答案 10 :(得分:6)

有一个非常好的库可以在其他漂亮的管道中执行此操作。它被称为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 -->

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

答案 11 :(得分:6)

这里没有任何答案对我有用,这对我有用:

使用内容创建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是一个很好的参考。

答案 12 :(得分:3)

这是简单的解决方案

您可以为此

使用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]
              }
            }
          }
    };
  }
}
  

http://plnkr.co/edit/GpmX8g?p=info

答案 13 :(得分:2)

将演示类型更改为数组 或遍历对象并推送到另一个数组

id_token

并来自html:

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

答案 14 :(得分:1)

我认为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个小时的谷歌搜索和诅咒..

(拍前额)

答案 15 :(得分:1)

您可以通过动态对象的键

myObj['key']

答案 16 :(得分:1)

使用索引:

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

用法:

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

答案 17 :(得分:0)

你现在必须这样做,我知道效率不高,因为你不想转换你从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;

    });