如何使用ngFor循环进行迭代Map包含键作为字符串,值作为映射迭代


109

我是angular 5的新手,并尝试迭代包含打字稿中另一张地图的地图。下面的角度如何在这种映射下进行迭代是组件的代码:

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>

运行时错误



什么是我不想我的地图转换成阵列解决方案
FEROZ西迪基


感谢工作很好
Feroz Siddiqui '18

Answers:


246

对于Angular 6.1+,您可以使用默认管道keyvalue(也可以进行回顾和支持):

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

工作演示


对于以前的版本:

一个简单的解决方案是将映射转换为数组: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

@FerozSiddiqui,我已经更新了答案,并且我认为它将适用于任何嵌套级别。
Vivek Doshi

如果最终将其转换为Array,我们将失去所有Map功能。那么Map的好处是什么?
diEcho

1
@ pro.mean,我们进行转换只是因为我们要通过角度模板遍历它,因为它需要一些可迭代的对象。而且您仍然map可以使用原始对象,则可以使用该对象来利用Map的所有好处
Vivek Doshi

1
@ pro.mean,我们已经转换为仅在模板侧显示,但是您仍然可以在组件侧使用Map对象。您可以向OP询问why he needed this kind of requirement,他可以为您更好地解释:)
Vivek Doshi

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

2
看来,键值不能保持地图的初始排序:-(,您需要添加比较器函数来解决这一问题
Konstantin Vahrushev

1
这是真的。这是一个问题github.com/angular/angular/issues/31420
Londeren

24

编辑

对于Angular 6.1和更高版本,请使用Londeren建议的KeyValuePipe

适用于Angle 6.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,则会看到它没有被多次调用。但是公认的解决方案中的组件方法确实...
大卫

1
我落后了!感谢您的
注意-Drenai

10

这是因为map.keys()返回迭代器。*ngFor可以与迭代器一起使用,但是map.keys()将在每个更改检测周期调用,从而生成对该数组的新引用,从而导致您看到错误。顺便说一句,这并不总是一个错误,你会传统不去想它。它甚至可能不会破坏您的任何功能,但建议您拥有一个看起来疯狂的数据模型-更改速度比更改检测器检查其值快。

如果您不想将映射转换为组件中的数组,则可以使用注释中建议的管道。似乎没有其他解决方法。

PS:此错误不会在生产模式下显示,因为它更像是一个非常严格的警告,而不是实际错误,但是,仍然要保留它不是一个好主意。


1

就像人们在评论中提到的那样,键值管道不保留插入顺序(这是Map的主要目的)。

无论如何,如果您有一个Map对象并想要保留顺序,则看起来最干净的方法是entrys()函数:

<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;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.