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

Par*_*ain 349 object typescript angular

我有点困惑如何获取keyvalue同时使用angular2对象的*ngFor用于遍历的对象.我知道在角度1.x中有一个类似的语法

ng-repeat="(key, value) in demo"
Run Code Online (Sandbox Code Playgroud)

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

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

demo = {
    'key1': [{'key11':'value11'}, {'key12':'value12'}],
    'key2': [{'key21':'value21'}, {'key22':'value22'}],
  }
Run Code Online (Sandbox Code Playgroud)

以下是我的尝试:http ://plnkr.co/edit/mIj619FncOpfdwrR0KeG?p=preview

我怎样才能获得key1key2动态使用*ngFor?经过广泛搜索后,我发现了使用管道的想法,但我不知道如何去做.是否有任何内置管道在angular2中做同样的事情?

tom*_*ico 343

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(){}
}
Run Code Online (Sandbox Code Playgroud)

  • 这是一种更好,更有效的解决方案 (24认同)

Par*_*ain 253

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

<div *ngFor="let item of testObject | keyvalue">
    Key: <b>{{item.key}}</b> and Value: <b>{{item.value}}</b>
</div>
Run Code Online (Sandbox Code Playgroud)

工作分叉示例

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

如果您使用的是Angular v5或更低版本,或者您想要使用管道,请按照以下答案操作

  • 您可以使用自定义比较器保留原始键顺序:`*ngFor ="let test of testObject | keyvalue:keepOriginalOrder"`并在您的类中定义:`public keepOriginalOrder =(a,b)=> a.key` (17认同)
  • 哈哈,我必须进行 ng6 更新才能访问这个管道 - 很棒的东西 - 谢谢 (3认同)
  • public keepOriginalOrder = (a, b) =&gt; a.key 非常感谢 (2认同)
  • @calios已经是一个可接受的答案:P (2认同)

Thi*_*ier 213

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

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

并使用它:

<tr *ngFor="let c of content">           
  <td *ngFor="let key of c | keys">{{key}}: {{c[key]}}</td>
</tr>
Run Code Online (Sandbox Code Playgroud)

编辑

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

@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;
  }
}
Run Code Online (Sandbox Code Playgroud)

并使用它:

<span *ngFor="let entry of content | keys">           
  Key: {{entry.key}}, value: {{entry.value}}
</span>
Run Code Online (Sandbox Code Playgroud)

  • 我实际上不鼓励任何人使用管道在`*ngFor`表达式中创建集合.它会产生巨大的性能瓶颈,因为每次变更检测器检查更改时都需要生成集合. (46认同)
  • 答案有点过时了.行*ngFor ="#content of contents | keys"行不正常,for ... in循环更好地改为"for(Object.keys(value)的const键)" (4认同)
  • 感谢您的解决方案...问题是,只要对象发生更改,管道就不会更新.如果我将"pure:false"添加到管道中,它将变得非常低效.每当我更改对象(删除项目)时,您是否有手动更新管道的解决方案? (3认同)
  • @RachChen不在模板中:`common:NgFor已被删除,因为自v4起已弃用。请改用NgForOf。这不会影响在模板中使用*ngFor。`(https://jaxenter.com/road-to-angular-5-133253.html) (2认同)

yur*_*zui 41

更新

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>
Run Code Online (Sandbox Code Playgroud)

Plunker示例

以前的版本

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

<div *ngFor="let key in obj">
   <b>{{ key }}</b>: {{ obj[key] }}
</div>
Run Code Online (Sandbox Code Playgroud)

Plunker示例

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);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)


Ger*_*rbó 38

从Angular 6.1,您可以使用keyvalue管道:

<div *ngFor="let item of testObject | keyvalue">
    Key: <b>{{item.key}}</b> and Value: <b>{{item.value}}</b>
</div>
Run Code Online (Sandbox Code Playgroud)

但是通过键值对结果列表进行排序是不方便的.如果你需要中立的东西:

@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;
  }
}
Run Code Online (Sandbox Code Playgroud)

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


Par*_*ain 23

用示例详述@ Thierry的答案.

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

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

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

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

和HTML部分是:

<ul>
  <li *ngFor='#key of demo | keys'>
   Key: {{key.key}}, value: {{key.value}}
  </li>
</ul>
Run Code Online (Sandbox Code Playgroud)

工作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>
Run Code Online (Sandbox Code Playgroud)


Ste*_*aul 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...
}
Run Code Online (Sandbox Code Playgroud)

  • 因为它会抛出:`TypeError:无法读取undefined`的属性'keys'.模板似乎不支持它. (8认同)
  • 那怎么比*ngFor里面的`Object.keys(...)`更好? (2认同)

Jer*_*itz 15

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

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

在打字稿文件中,包括:

import * as _ from 'lodash';
Run Code Online (Sandbox Code Playgroud)

在导出的组件中,包括:

_: any = _;
Run Code Online (Sandbox Code Playgroud)


Sha*_*lva 11

考虑为 Angular 8 添加答案:

对于循环,您可以执行以下操作:

<ng-container *ngFor="let item of BATCH_FILE_HEADERS | keyvalue: keepOriginalOrder">
   <th nxHeaderCell>{{'upload.bulk.headings.'+item.key |translate}}</th>
</ng-container>
Run Code Online (Sandbox Code Playgroud)

另外,如果您需要上述数组来保持原始顺序,请在您的类中声明:

public keepOriginalOrder = (a, b) => a.key;
Run Code Online (Sandbox Code Playgroud)


Are*_*efe 9

您可以使用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>
Run Code Online (Sandbox Code Playgroud)


Ada*_*ass 8

感谢管道,但我必须做一些更改才能在角度2 RC5中使用它.更改了Pipe导入行,并且还为keys数组初始化添加了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;
  }
}
Run Code Online (Sandbox Code Playgroud)


Ado*_*uez 8

使用指数:

<div *ngFor="let value of Objects; index as key">
Run Code Online (Sandbox Code Playgroud)

用法:

{{key}} -> {{value}}
Run Code Online (Sandbox Code Playgroud)

  • 这对我来说是新事物,如果您可以在答案中添加示例,那就更好了 :) 另外,您能指出我的任何文档吗? (2认同)
  • 在此示例中,“键”是索引。这与问题无关,并且无法访问真正的密钥 (2认同)

cjo*_*son 7

这里没有任何答案对我来说是开箱即用的,这对我有用:

创建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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

import { KeysPipe } from './pipes/keys';
Run Code Online (Sandbox Code Playgroud)

然后添加到您的模块声明数组,如下所示:

@NgModule({
    declarations: [
        KeysPipe
    ]
})
export class AppModule {}
Run Code Online (Sandbox Code Playgroud)

然后在您的视图模板中,您可以使用以下内容:

<option *ngFor="let entry of (myData | keys)" value="{{ entry.key }}">{{ entry.value }}</option>
Run Code Online (Sandbox Code Playgroud)

如果您想了解更多,我发现是一个很好的参考.


Ric*_*ock 6

有一个非常好的库,可以在其他漂亮的管道中执行此操作.它叫做ngx-pipes.

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

钥匙管

<div *ngFor="let key of {foo: 1, bar: 2} | keys">{{key}}</div> 
<!-- Output: 'foo' and 'bar -->
Run Code Online (Sandbox Code Playgroud)

价值管道

<div *ngFor="let value of {foo: 1, bar: 2} | values">{{value}}</div>
<!-- Output: 1 and 2 -->
Run Code Online (Sandbox Code Playgroud)

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

  • 很好的替代方案,但问题是如果我们可以使用像管道这样的简单代码来做到这一点,为什么要使用外部库来实现简单的代码和平 (2认同)
  • 嗯......但它是管道?在导入库时,它只是package.json中的一行和模块中的另外两行.另一方面,自定义管道需要一个单独的文件,其中包含大约10-20行代码以及模块中的导入行.我们发现在我们的项目中使用ngx-pipes非常容易.我们为什么要重新发明轮子?:) (2认同)
  • 不要忘记,如果您编写自定义管道,您还必须测试该自定义管道*.这就是10-20行管道代码,然后可能有20-40行测试代码来测试管道. (2认同)