文字列としてキーを含み、マップ反復として値を含むngForループマップを使用して反復する方法


109

私はAngular5を初めて使用し、typescriptに別のマップを含むマップを反復しようとしています。この種のマップの下を角度で繰り返す方法は、コンポーネントのコードです。

import { Component, OnInit} from '@angular/core';

@Component({
  selector: 'app-map',
  templateUrl: './map.component.html',
  styleUrls: ['./map.component.css']
})
export class MapComponent implements OnInit {
  map = new Map<String, Map<String,String>>();
  map1 = new Map<String, String>();

  constructor() { 


  }

  ngOnInit() {
    this.map1.set("sss","sss");
    this.map1.set("aaa","sss");
    this.map1.set("sass","sss");
    this.map1.set("xxx","sss");
    this.map1.set("ss","sss");


    this.map1.forEach((value: string, key: string) => {
      console.log(key, value);

    });


    this.map.set("yoyoy",this.map1);

  }



}

そしてそのテンプレートhtmlは:

<ul>
  <li *ngFor="let recipient of map.keys()">
    {{recipient}}
   </li>


</ul>

<div>{{map.size}}</div>

ランタイムエラー



マップを配列に変換したくない解決策は何
ですか


おかげで非常にうまくいきます
FerozSiddiqui18年

回答:


245

Angular 6.1以降の場合、デフォルトのパイプを使用できますkeyvalueレビューと賛成も行います):

<ul>
    <li *ngFor="let recipient of map | keyvalue">
        {{recipient.key}} --> {{recipient.value}}
    </li>
</ul>

ワーキングデモ


以前のバージョンの場合:

これに対する簡単な解決策の1つは、マップを配列に変換することです:Array.from

コンポーネント側:

map = new Map<String, String>();

constructor(){
    this.map.set("sss","sss");
    this.map.set("aaa","sss");
    this.map.set("sass","sss");
    this.map.set("xxx","sss");
    this.map.set("ss","sss");
    this.map.forEach((value: string, key: string) => {
        console.log(key, value);
    });
}

getKeys(map){
    return Array.from(map.keys());
}

テンプレート側:

<ul>
  <li *ngFor="let recipient of getKeys(map)">
    {{recipient}}
   </li>
</ul>

ワーキングデモ


1
map = new Map <String、Map <String、String >>();の場合 それはどのように機能しますか?
Feroz Siddiqui 2018年

@FerozSiddiqui、私は答えを更新しました、そしてそれはどんなネストされたレベルでもうまくいくと思います。
Vivek Doshi 2018

最終的に配列に変換すると、すべてのマップ機能が失われます。では、マップの利点は何ですか?
diEcho 2018年

1
@ pro.mean、反復可能なものが必要なため、角度テンプレートを介してループしたいという理由だけで変換しています。元のオブジェクトがまだmap利用可能であり、そのオブジェクトを使用してMapのすべての利点を使用できます
Vivek Doshi 2018

1
@ pro.mean、テンプレート側でそれを示すためだけに変換しましたが、コンポーネント側で使用できるMapオブジェクトがまだあります。あなたはOPwhy he needed this kind of requirementに尋ねることができます、彼はあなたをよりよく説明することができます:)
Vivek Doshi 2018

48

Angular 6.1以降を使用している場合、最も便利な方法はKeyValuePipeを使用することです

   @Component({
      selector: 'keyvalue-pipe',
      template: `<span>
        <p>Object</p>
        <div *ngFor="let item of object | keyvalue">
          {{item.key}}:{{item.value}}
        </div>
        <p>Map</p>
        <div *ngFor="let item of map | keyvalue">
          {{item.key}}:{{item.value}}
        </div>
      </span>`
    })
    export class KeyValuePipeComponent {
      object: Record<number, string> = {2: 'foo', 1: 'bar'};
      map = new Map([[2, 'foo'], [1, 'bar']]);
    }

3
うまくいけば、人々がスクロールしてこの答えを見ることができます。なぜなら、このすぐに使えるパイプが私のmapタイプで使用できるのを見るまで、リファクタリングを実行しようとしていたからです*ngFor
atconway 2018年

2
keyvalueはマップの初期ソートを保持していないようです:-(、それを修正するには比較関数を追加する必要があります
KonstantinVahrushev20年

1
これは本当です。そして、ここで問題ですgithub.com/angular/angular/issues/31420は
Londeren

24

編集

Angular 6.1以降の場合は、Londerenが提案するKeyValuePipeを使用してください。

Angular6.0以前の場合

物事を簡単にするために、パイプを作成できます。

import {Pipe, PipeTransform} from '@angular/core';

@Pipe({name: 'getValues'})
export class GetValuesPipe implements PipeTransform {
    transform(map: Map<any, any>): any[] {
        let ret = [];

        map.forEach((val, key) => {
            ret.push({
                key: key,
                val: val
            });
        });

        return ret;
    }
}

 <li *ngFor="let recipient of map |getValues">

純粋であるため、すべての変更検出でトリガーされるわけではなく、map変数への参照が変更された場合にのみトリガーされます。

Stackblitzデモ


パイプは「純粋」ではないため、変更がないかチェックされ、変更検出サイクルごとに完全に繰り返されると思います。反対票を投じませんでしたが、多分それが理由ですか?
ドレナイ

5
@Ryanパイプはデフォルトで純粋です。パイプにconsole.logを追加すると、複数回呼び出されないことがわかります。しかし、受け入れられたソリューションのコンポーネントメソッドは...
David

1
私はそれを逆にした!頭を上げてくれてありがとう
Drenai 2018年

10

これはmap.keys()、イテレータを返すためです。*ngForイテレータを使用できますが、map.keys()は変更検出サイクルごとに呼び出されるため、配列への新しい参照が生成され、エラーが発生します。ちなみに、これはあなたが伝統的に考えているように必ずしもエラーではありません。機能を損なうことはないかもしれませんが、非常識な方法で動作しているように見えるデータモデルがあることを示唆しています-変更検出器がその値をチェックするよりも速く変更します。

マップをコンポーネント内の配列に変換したくない場合は、コメントで提案されているパイプを使用できます。見たところ、他の回避策はありません。

PSこのエラーは、実際のエラーというよりも非常に厳密な警告のようなものであるため、本番モードでは表示されませんが、それでも、そのままにしておくことはお勧めできません。


1

コメントで言及されているように、KeyValueパイプは挿入の順序を保持しません(これがMapの主な目的です)。

とにかく、Mapオブジェクトがあり、順序を保持したい場合、そのための最もクリーンな方法は、entries()関数です。

<ul>
    <li *ngFor="let item of map.entries()">
        <span>key: {{item[0]}}</span>
        <span>value: {{item[1]}}</span>
    </li>
</ul>

github.com/angular/angular/issues/31420#issuecomment-635377113を参照してください。.entries()の使用を避けるべき理由
Florian

1

以下のコードは、マップの挿入順序で表示するのに役立ちます。

<ul>
    <li *ngFor="let recipient of map | keyvalue: asIsOrder">
        {{recipient.key}} --> {{recipient.value}}
    </li>
</ul>

.tsファイルは以下のコードを追加します。

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