web-dev-qa-db-ja.com

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

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

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

しかし、私はangle2で同じことをする方法がわかりません。私は成功しないで、似たようなことを試みました:

<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で同じことをするための作り付けのパイプはありますか?

281
Pardeep Jain

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>

動作中の分岐例

もっと役に立つ情報はここをチェックしてください -

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

152
Pardeep Jain

テンプレート内で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(){}
}
295
tomtastico

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

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

更新

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

例を使って@ Thierryの答えを詳しく説明します。

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

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

**変換方法はパイプにとって不可欠です。 PipeTransformインタフェースはそのメソッドを定義し、ツールとコンパイラの両方をガイドします。オプションです。 Angularは、関係なく、transformメソッドを探して実行します。より多くの情報に関しては管について ここに参照しなさい

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>

Working 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>
23
Pardeep Jain

Angular 6.1から keyvalue pipeを使用できます。

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

19
Gerard Carbó

@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...
}
18
Stephen Paul

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

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

TypeScriptファイルに、次のものを含めます。

import * as _ from 'lodash';

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

_: any = _;
15
Jeremy Moritz

パイプをありがとう、私はそれを角度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;
  }
}
8
Adam Winnipass

他のNiceパイプの中でこれを行う本物のNiceライブラリがあります。 ngx-pipe と呼ばれます。

たとえば、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 -->

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

6
RichieRock

ここでの答えのどれも箱から出して私のために働かなかった、ここで私のために働いたのはここにある:

コンテンツを含む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>

ここ あなたがもっと読みたいのなら私が見つけた良い参考文献です。

6
cjohansson

これが簡単な解決策です

これには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
sudheer KB

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

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

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

myObj['key']
1
Rizo

インデックスを使用:

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

使用法:

{{key}} -> {{value}}
1
Adonias Vasquez

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

あなたは今のところこのようにそれをしなければなりません、あなたが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;

    });
0
kevinius