ChatGPT解决这个技术问题 Extra ChatGPT

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

我对在使用 *ngFor 迭代对象时如何在 angular2 中获取对象的 keyvalue 感到有些困惑。我知道在 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 动态获取 key1key2?经过广泛搜索,我发现了使用管道的想法,但我不知道如何去做。在angular2中是否有任何内置管道可以做同样的事情?

目前在 angular2 ngFor 中不支持 key, value 对类型的语法,您应该查看 this answer
@PankajParkar 是的,已经阅读了这个答案。现在有什么替代品吗?
@Pradeep我现在没有想到任何其他方法,您应该为此创建自己的 Pipe ..
嗯,但我不知道如何为它创建管道。
我给你参考的@Pradeep 答案有这个实现。他们应该工作..

T
Top-Master

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 访问对象的键和值


大声笑我不得不做一个 ng6 更新只是为了访问这个管道 - 很棒的东西 - thx
您可以使用自定义比较器保持原始键顺序:*ngFor="let item of testObject | keyvalue:keepOriginalOrder" 并在您的类中定义:public keepOriginalOrder = (a, b) => a.key
public keepOriginalOrder = (a, b) => a.key 非常感谢这个
这应该是答案 - 在 angular 7 上运行良好
令人难以置信的是,自从第一个版本以来,它就不存在了
t
tomtastico

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

这是一个更好、更有效的解决方案
@tomtastico 你将如何为 3D 数组显示这个?例如 {"1": {"1.1": ["1.1.1","1.1.2"]}}。然后嵌套3个ngFor
@Frank 你自己说的。嵌套 *ngFor。前两个使用 objectKeys,最里面不需要(因为它只是一个数组)。
惊人的。设置 objectKeys = Object.keys 是我见过的能够从 HTML 检查对象长度的最简单方法。
M
Muhammad Shaharyar

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

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 添加到管道,它会变得非常低效。每当我更改对象(删除项目)时,您是否有手动更新管道的解决方案?
答案有点过时了。行 *ngFor="#entry of content | keys" 不能正常工作,for ... in 循环最好改为“for (const key of Object.keys(value))”
@RachChen 不在模板中: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)
y
yurzui

更新

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

G
Gerard Carbó

从 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 管道属性。在这种情况下,管道会在每个更改检测周期中调用,即使输入引用没有更改(向对象添加属性时也是如此)。


已经在 stackoverflow.com/a/51491848/5043867 上分享了相同的答案
@PardeepJain 请让其他人也分享:)!答案的第二部分是我需要的
@minigeek 不同的解决方案总是受欢迎的伙伴。但是,当我发布评论时,您所指的第二部分丢失了,只有第一部分与已接受的答案重复。您可以查看答案历史记录的更改日志。
@PardeepJain。是的,你的回答和那个人的评论只帮助我解决了问题。我理解你的观点抄袭的感觉:p
C
Community

举例说明@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>

这需要更新:这是我在表达式中得到“#”的警告已被弃用。改用“让”! (" -->
  • ]*ngFor='#key of demo| keys'> 键:{{key.key}},值:{ {key.value}}
  • "): myComponent@56:6
不确定这是否是新的,但可以从文档中引用: > 我们必须将管道包含在 AppModule 的声明数组中。
S
Stephen Paul

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

这比 *ngFor 中的 Object.keys(...) 有什么好处?
因为它会抛出:TypeError: Cannot read property 'keys' of undefined。模板中似乎不支持它。
这作为一种解决方案非常有效,并且避免了上面指出的性能问题。 stackoverflow.com/questions/35534959/…
你好,这个 b 可以不在 template 选项中使用,而是在模板的实际 html 代码中使用吗?谢谢
J
Jeremy Moritz

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

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

在打字稿文件中,包括:

import * as _ from 'lodash';

在导出的组件中,包括:

_: any = _;

对不起,但不需要使用像 Lodash 这样的额外库来处理这些事情。无论如何,总是欢迎新方法:)
J
Juliyanage Silva

考虑为 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;

如果您也添加工作示例会很棒,stackblitz 可能是
@PardeepJain,我想要更复杂的。
W
Winnipass

感谢管道,但我必须先进行一些更改,然后才能在 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;
  }
}

是的,进口已经改变
c
cjohansson

这里没有一个答案对我有用,这对我有用:

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


我可以知道您的答案与上面提供的其他答案(仅使用管道)之间有什么区别吗?好像和上面一样
当然 1. 上面的示例使用 *ngFor="#entry" 而不是 *ngFor="let entry of" 并且我的编译器不接受 #entry 语法,参考也不使用 #。 “let entry of (myData | keys)”似乎是一个更好的解决方案。 2. 我的编译器也没有验证示例管道类,因为它缺少显式数据类型,所以我添加了它。 3.上面的例子没有显示如何将管道集成到我的回答所做的项目中,您需要将它导入到主模块中。
哈哈,是的,是的,因为当时给出了答案,包括#等语法。顺便说一句,你的答案无疑也是正确的
A
Adonias Vasquez

使用指数:

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

用法:

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

这对我来说是新事物,如果您可以在答案中添加示例,那就更好了:)您还可以为我指出任何相同的文档吗?
对象的类型是什么?数组还是地图?请说清楚。提前致谢
在此示例中,“键”是索引。这与问题无关,无法访问真正的密钥
A
Arefe

您可以使用 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>

R
RichieRock

在其他不错的管道中,有一个非常好的库可以做到这一点。它称为 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 -->

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


很好的替代品,但是如果我们可以使用像管道这样的简单代码来做到这一点,为什么要使用外部库来实现简单的代码和平
嗯......但它是一个管道?当您导入库时,它只是您的 package.json 中的一行和模块中的另外两行。另一方面,自定义管道需要一个单独的文件,其中包含大约 10-20 行代码以及模块中的导入行。我们发现在我们的项目中使用 ngx-pipes 非常容易。我们为什么要重新发明轮子? :)
是的,毫无疑问,实际上它是基于意见的,您可以在这两者之间进行选择,没有一个是错误的方式。
不要忘记,如果您编写自定义管道,则还必须测试该自定义管道。所以这是 10-20 行管道代码,然后可能是 20-40 行测试代码来测试管道。
S
Sudheer KB

这是简单的解决方案

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

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


M
Mohammad Reza Mrg

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

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>

这不是一个合适的方法,任何人都可以很容易地做到这一点。
C
Ciarán Bruen

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

(拍了拍额头)


k
kevinius

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

    });

R
Rizwan

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

myObj['key']

你是认真的?
W
Wesley Gonçalves

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.values(object);将给出一个值列表,而不是键,所要求的值。
对不起,@比尔。我更改了返回键值对的方法,而不仅仅是返回值。您可以使用 Object.entries 而不是使用 Object.values。感谢您指出了这一点。
E
Emmanuel Iyen-Mediatrees

像这样创建你的数组

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

一直在工作