* ngForを使用してオブジェクトのキーと値にアクセスする


426

オブジェクトの反復に使用しているときに、angular2でオブジェクトのkeyand を取得する方法について少し混乱しています。私はangular 1.xで次のような構文があることを知っていますvalue*ngFor

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

どのように私は得ることができますkey1し、key2使用して動的に*ngFor?広範囲に検索した後、パイプを使用するアイデアを見つけましたが、どうすればよいかわかりません。angular2で同じことをするための組み込みのパイプはありますか?


2
現在key, value、angular2 ngForにはペアの種類の構文はサポートされていません。この答え
Pankaj Parkar

@PankajParkarええすでにこの答えを読んでいます。今のところ代替はありますか?
Pardeep Jain、2016

私は今、このために他の方法ではないと思う@Pradeep、あなたは自分を作成するために行く必要がありPipe、このために...
パンカジパーカー

うーん、私は同じためにパイプを作成する方法がわかりません。
Pardeep Jain、2016

参考までに提供した@Pradeepの回答には、その実装が含まれています。彼らは動作するはずです..
パンカジパーカー2016

回答:


399

持っている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(){}
}


25
これはより優れた、より効率的なソリューションです
Aous1000

1
@tomtastico 3D配列でこれをどのように表示しますか?たとえば、{"1":{"1.1":["1.1.1"、 "1.1.2"]}}。そして、3つのngForをネストする
フランク

@フランクあなたは自分でそれを言っただけです。ネスト*ngFors。最初の2つはを使用しobjectKeys、最も内側は必要ありません(これは単なる配列であるため)。
tomtastico 2018年

1
驚くばかり。objectKeys = Object.keysを設定することは、HTMLからオブジェクトの長さを確認できることがわかった最も簡単な方法です。
JAC

394

以下のように角度の最新リリース(V6.1.0) 、角度チームとして名前と同じのためのパイプに構築された新しいを追加しましたkeyvalueあなたはで、オブジェクト、マップ、および配列を通じてヘルプをパイプ反復処理をcommon、角度、パッケージのモジュール。例えば ​​-

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

フォークの例

より役立つ情報については、こちらをご覧ください-

Angular v5以下を使用している場合、またはパイプを使用して達成したい場合は、この回答に従ってください


1
笑私はこのパイプにアクセスするためだけにng6更新を行わなければなりませんでした-素晴らしいもの
-thx

36
カスタムコンパレータを使用して、元のキーの順序を維持することができます *ngFor="let item of testObject | keyvalue:keepOriginalOrder" し、あなたのクラスで定義: public keepOriginalOrder = (a, b) => a.key
マイク- shtil

2
public keepOriginalOrder =(a、b)=> a.key thxこれにはたくさん
Kumaresan Perumal

1
これが答えになるはずです
。angular7で

1
信じられないほど、これは最初のバージョン以来存在しませんでした
CarlosPinzón19/

227

各要素のキーのリストを返すカスタムパイプを作成できます。そんな感じ:

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>

1
閉じ括弧が欠落していることに注意してくださいkeys.push({key: key, value: value[key]);
Marton Pallagi 2016

49
実際には、式を使用してコレクションを作成するためにパイプを使用しないようにしています*ngFor。変更検出機能が変更をチェックするたびにコレクションを生成する必要があるため、パフォーマンスのボトルネックが非常に大きくなります。
2016

3
解決策をありがとう...問題は、オブジェクトが変更されるたびにパイプが更新されないことです。pure:falseパイプに追加すると、非常に非効率になります。オブジェクトを変更する(アイテムを削除する)たびにパイプを手動で更新するソリューションはありますか?
ncohen 2017年

4
答えは少し時代遅れです。行* ngFor = "#entry of content | keys"は適切に機能せず、for ... inループは "for(const key of Object.keys(value))"に変更した方がよい
実験者

2
@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
mwld '16 / 11/17

49

更新

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

43

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パイプ属性を指定することを忘れないでください。この場合、入力参照が変更されていなくても、変更検出サイクルごとにパイプが呼び出されます(オブジェクトにプロパティを追加する場合も同様)。



26

例を用いた@Thierryの回答の詳細。

key and value* ngForループから取得する組み込みのパイプまたはメソッドはありません。同じためにカスタムパイプを作成する必要があります。thierryがここで言ったように、コードでの答えです。

** pipeクラスは、入力値とオプションのパラメーター文字列の配列を取り、変換された値を返すPipeTransformインターフェースの変換メソッドを実装します。

**変換メソッドはパイプに不可欠です。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;
  }
}

そして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>

これは更新する必要があります。式の中に「#」が表示されるという警告は次のとおりです。代わりに「let」を使用してください!( "</ li>-> <ul * ngIf =" demo "> <li [ERROR->] * ngFor = '#key of demo | keys'>キー:{{key.key}}、値:{ {key.value}} </ li> "):myComponent @ 56:6
user6123723

これが新しいものかどうかはわかりませんが、ドキュメントから引用すると、次のようになります。> AppModuleの宣言配列にパイプを含める必要があります。
Akzidenzgrotesk

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

2
そしてそれはObject.keys(...)* ngForの内部よりもどうですか?
Simon_Weaver

8
それがスローされるので:TypeError: Cannot read property 'keys' of undefined。テンプレートではサポートされていないようです。
スティーブンポール

1
これは解決策として非常にうまく機能し、上で指摘したパフォーマンスの問題を回避します。stackoverflow.com/questions/35534959/…–
J.

こんにちは、これはtemplateオプションではなくテンプレートの実際のHTMLコードで使用できますか?ありがとう
Scaramouche

16

Lodashを既に使用している場合は、キーと値の両方を含む次の簡単なアプローチを実行できます。

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

typescriptファイルに以下を含めます。

import * as _ from 'lodash';

エクスポートされたコンポーネントには、次のものが含まれます。

_: any = _;

申し訳ありませんが、そのようなもののためにLodashのような追加のライブラリを使用する必要はありません。とにかく新しい方法はいつでも歓迎します:)
Pardeep Jain

8

パイプに感謝しますが、angular 2 RC5で使用する前にいくつか変更を加える必要がありました。パイプのインポート行を変更し、タイプの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;
  }
}

はい、インポートが変更されました
Pardeep Jain

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

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>

ここであなたはもっと読みたい場合は私が見つけた良いの参照です。


あなたの答えと他の答え(パイプのみを使用)の違いは何ですか?それは上記と同じように見えます
パーディープ・ジェイン

1
確かに1.上記の例では、* ngFor = "let entry of"の代わりに* ngFor = "#entry"を使用しており、コンパイラーは#entry構文を受け入れず、参照も#を使用していません。「(myData | keys)のエントリを許可する」がより良い解決策のようです。2.明示的なデータ型が欠落していたため、コンパイラーはサンプルパイプクラスも検証しなかったため、追加しました。3.上記の例は、パイプをプロジェクトに統合する方法を示していません。私の答えは、メインモジュールにインポートする必要があることです。
cjohansson

答えは含めてその時の構文で与えられたときのでoffcoureseはい(笑)、#などところであなたの答えも間違いなく修正される
Pardeepジャイナ

6

他の素晴らしいパイプの中でこれを行う本当の素晴らしいライブラリがあります。これはngx-pipesと呼ばれます。

たとえば、keys pipeはオブジェクトのキーを返し、values pipeはオブジェクトの値を返します。

キーパイプ

<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 -->

独自のカスタムパイプを作成する必要はありません:)


2
良い代替案ですが、パイプのような単純なコードを使用してこれを行うことができる場合、単純なコードの平和のために外部ライブラリを使用する理由は何
ですか

2
えっと…でもパイプ?ライブラリをインポートすると、package.jsonの1行とモジュールの別の2行になります。一方、カスタムパイプには、約10〜20行のコードを含む個別のファイルと、モジュール内のインポート行が必要です。私たちのプロジェクトでは、ngx-pipesを使用するのは非常に簡単です。なぜ車輪を再発明する必要があるのですか?:)
RichieRock 2017年

間違いなく、実際にはその意見に基づいており、これら2つの中からどちらかを選択できます。
Pardeep Jain

2
カスタムパイプを作成する場合は、そのカスタムパイプテストする必要があることを忘れないでください。つまり、これは10〜20行のパイプコード、そしておそらくパイプをテストするための20〜40行のテストコードです。
danwellman 2018年

4

インデックスを使用:

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

使用法:

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

1
それは私にとって新しいものです、あなたの答えと一緒に例を追加することができればもっと良いです:)また、あなたは同じことについてのドキュメントを私に指摘できますか?
Pardeep Jain

オブジェクトのタイプは何ですか?配列またはマップ?明確にしてください。よろしくお願いします
バジルモハメッド

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


3

デモタイプを配列に変更するか、オブジェクトを反復処理して別の配列にプッシュする

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>

これは適切な方法ではなく、誰でも簡単に実行できます。
Pardeep Jain

1

Object.keysがこの問題の最良の解決策だと思います。この答えに遭遇し、Object.keysが['key1'、 'key2']ではなく['0'、 '1']を与える理由を調べようとしている人は、注意書きとして、「の "と"の ":"

私はすでに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時間を要しました。

(額を平手打ち)


1

これを試すことで動的オブジェクトのキーを取得できます

myObj['key']

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;

    });
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.