关于angular:使用* ngFor访问对象的键和值

access key and value of object using *ngFor

我对如何在使用*ngFor遍历对象时如何在angular2中获取对象的keyvalue感到困惑。 我知道在angular 1.x中有一种语法

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
<ul>

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


</ul>


demo = {
    'key1': [{'key11':'value11'}, {'key12':'value12'}],
    'key2': [{'key21':'value21'}, {'key22':'value22'}],
  }

这是我的尝试:

如何使用*ngFor动态获取key1key2? 经过广泛搜索之后,我发现了使用管道的想法,但是我不知道该怎么做。
在angular2中是否有用于执行相同操作的内置管道?


在模板中可以访问Object.keys并在*ngFor中使用它。

1
2
3
4
5
6
7
8
9
10
@Component({
  selector: 'app-myview',
  template: `{{key + ' : ' + items[key]}}`
})

export class MyComponent {
  objectKeys = Object.keys;
  items = { keyOne: 'value 1', keyTwo: 'value 2', keyThree: 'value 3' };
  constructor(){}
}


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

1
    Key: {{item.key}} and Value: {{item.value}}

工作分叉的例子

在这里查看更多有用的信息-

  • https://github.com/angular/angular/blob/master/CHANGELOG.md#features-3
  • https://github.com/angular/angular/commit/2b49bf7

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

  • 使用ngfor访问对象的键和值


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

1
2
3
4
5
6
7
8
9
10
11
12
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;
  }
}

并像这样使用它:

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

编辑

您还可以返回包含键和值的条目:

1
2
3
4
5
6
7
8
9
10
@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;
  }
}

并像这样使用它:

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


更新

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

1
  {{ item.key }} - {{ item.value }}

柱塞示例

先前版本

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

1
   {{ key }}: {{ obj[key] }}

柱塞示例

ngforin.directive.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@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;

      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中,您可以使用键值管道:

1
    Key: {{item.key}} and Value: {{item.value}}

但是它不方便按键值对结果列表进行排序。
如果您需要中立的东西:

1
2
3
4
5
6
7
8
9
10
11
12
@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的内置管道或方法。所以我们必须为它创建自定义管道。正如thierry所说的,这就是代码的答案。

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

**变换方法对于管道至关重要。 PipeTransform接口定义该方法,并指导工具和编译器。它是可选的; Angular无论如何都会寻找并执行transform方法。
有关管道的更多信息,请参阅此处

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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部分是:

1
2
3
4
5
6
7
8
9
<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所建议(感谢)在评论中此处为更新。

1
2
3
4
5
6
7
8
9
<ul>

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


</ul>


@Marton对接受的答案有重要的反对意见,理由是管道在每次更改检测时都会创建一个新的集合。相反,我将创建一个HtmlService,它提供一系列实用程序功能,该视图可以按如下方式使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Component({
  selector: 'app-myview',
  template: `{{i + ' : ' + items[i]}}`
})
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,则可以执行以下简单方法,其中包括键和值:

1
2
3
4
5
6
7
<ul>

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


</ul>

在打字稿文件中,包括:

1
import * as _ from 'lodash';

在导出的组件中,包括:

1
_: any = _;


感谢管道,但我必须进行一些更改才能在angular 2 RC5中使用它。更改了Pipe导入行,并在key数组初始化中添加了any的类型。

1
2
3
4
5
6
7
8
9
10
11
12
 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

1
2
3
4
5
6
7
8
9
10
11
12
13
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(您的主模块):

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

然后将如下所示的内容添加到模块声明数组中:

1
2
3
4
5
6
@NgModule({
    declarations: [
        KeysPipe
    ]
})
export class AppModule {}

然后,在您的视图模板中,您可以使用如下代码:

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

如果您想了解更多信息,这是一个很好的参考。


有一个真正的漂亮库在其他漂亮的管道中执行此操作。这就是ngx-pipes。

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

钥匙管

1
2
{{key}}
<!-- Output: 'foo' and 'bar -->

价值观管道

1
2
{{value}}
<!-- Output: 1 and 2 -->

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


使用索引:

1
 

用法:

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


这是简单的解决方案

您可以为此使用打字稿迭代器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import {Component} from 'angular2/core';
declare var Symbol;
@Component({
    selector: 'my-app',
    template:`
    <h4>Iterating an Object using Typescript Symbol</h4>
Object is : <p>
{{obj | json}}
</p>

============================
Iterated object params are:

{{o}}


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


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

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

和从HTML:

1
2
3
4
5
6
7
8
9
  <p>
{{obj.key}}
</p>
  <p>
{{obj.value}}
</p>
  <p>

</p>


您可以通过尝试这样做来获得动态对象的密钥

1
myObj['key']

我认为Object.keys是解决此问题的最佳方法。对于遇到此问题并试图找出Object.keys为什么要给它们['0','1']而不是['key1','key2']的人,请注意一个故事-当心"的"和"中:

我已经在使用Object.keys,类似于以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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;
}

但是,代替

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

我无意间写了

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

哪个"工作"完美无误,然后返回

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

这花了我大约2个小时的时间进行谷歌搜索和诅咒。

(拍打额头)


您现在必须这样做,我知道效率不是很高,因为您不想转换从firebase收到的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    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;

    });