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

How to iterate using ngFor loop Map containing key as string and values as map iteration

我对Angle 5还是陌生的,并尝试迭代包含typescript中另一张地图的地图。
如何在angular下迭代这种地图
以下是组件的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<ul>

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




</ul>


{{map.size}}

runtime


对于Angular 6.1,您可以使用默认管道keyvalue(也请同时进行评论和投票):

1
2
3
4
5
6
7
8
9
<ul>

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


</ul>

工作演示

对于先前版本:

一个简单的解决方案是将映射转换为数组:Array.from

组件侧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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());
}

模板侧:

1
2
3
4
5
6
7
8
9
<ul>

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


</ul>

工作演示


如果您使用的是Angular 6.1或更高版本,最方便的方法是使用KeyValuePipe

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
   @Component({
      selector: 'keyvalue-pipe',
      template: `<span>
        <p>Object</p>
       
          {{item.key}}:{{item.value}}
       
        <p>Map</p>
       
          {{item.key}}:{{item.value}}
       
      </span>`
    })
    export class KeyValuePipeComponent {
      object: Record<number, string> = {2: 'foo', 1: 'bar'};
      map = new Map([[2, 'foo'], [1, 'bar']]);
    }


编辑

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

对于Angle 6.0和更早版本

为简化操作,您可以创建管道。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import {Pipe, PipeTransform} from '@angular/core';

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

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

        return ret;
    }
}

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

就其本身而言,它不会在每次更改检测时都被触发,只有在对map变量的引用发生更改时才触发

Stackblitz演示


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

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

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


以下代码可用于按地图插入顺序显示。

1
2
3
4
5
6
7
8
9
<ul>

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


</ul>

.ts文件添加以下代码。

1
2
3
asIsOrder(a, b) {
    return 1;
}

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

无论如何,如果您有一个Map对象并想保留订单,那么最干净的方法是entrys()函数:

1
2
3
4
5
6
7
8
9
10
<ul>

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


</ul>


可以使用

Angulara的keyvalue管道,但不幸的是,它是按键排序的。地图已经下订单了,能够保留它会很棒!

我们可以定义自己的管道mapkeyvalue,该管道保留地图中项目的顺序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { Pipe, PipeTransform } from '@angular/core';

// Holds a weak reference to its key (here a map), so if it is no longer referenced its value can be garbage collected.
const cache = new WeakMap<ReadonlyMap, Array<{ key: any; value: any }>>();

@Pipe({ name: 'mapkeyvalue', pure: true })
export class MapKeyValuePipe implements PipeTransform {
  transform<K, V>(input: ReadonlyMap<K, V>): Iterable<{ key: K; value: V }> {
    const existing = cache.get(input);
    if (existing !== undefined) {
      return existing;
    }

    const iterable = Array.from(input, ([key, value]) => ({ key, value }));
    cache.set(input, iterable);
    return iterable;
  }
}

它可以这样使用:

1
2
3
4
5
<mat-select>
  <mat-option *ngFor="let choice of choicesMap | mapkeyvalue" [value]="choice.key">
    {{ choice.value }}
  </mat-option>
</mat-select>