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

Fer*_*qui 58 typescript angular-cli 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);

  }



}
Run Code Online (Sandbox Code Playgroud)

它的模板html是:

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


</ul>

<div>{{map.size}}</div>
Run Code Online (Sandbox Code Playgroud)

运行时错误

Viv*_*shi 115

对于Angular 6.1+,您可以使用默认管道keyvalue(可以查看):

<ul>
    <li *ngFor="let recipient of map | keyvalue">
        {{recipient.key}} --> {{recipient.value}}
    </li>
</ul>
Run Code Online (Sandbox Code Playgroud)

工作演示


对于以前的版本:

一个简单的解决方案是将map转换为array: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());
}
Run Code Online (Sandbox Code Playgroud)

模板面:

<ul>
  <li *ngFor="let recipient of getKeys(map)">
    {{recipient}}
   </li>
</ul>
Run Code Online (Sandbox Code Playgroud)

工作演示


Lon*_*ren 30

如果您使用的是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']]);
}
Run Code Online (Sandbox Code Playgroud)

  • 希望人们滚动并看到这个答案,因为我要做一个重构,直到我看到这个开箱即用的管道可用于我的`map`类型,它负责使用`*ngFor` (3认同)
  • 看来,keyvalue 没有保留地图的初始排序:-(,您需要添加比较器函数来解决这个问题 (3认同)

Dav*_*vid 20

编辑

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

角度为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">
Run Code Online (Sandbox Code Playgroud)

由于它是纯粹的,因此不会在每次更改检测时触发,只有在对map变量的引用发生更改时才会触发

Stackblitz演示

  • @Ryan管道默认是纯粹的.如果在管道中添加console.log,您将看到它不会多次调用.但公认解决方案中的组件方法确实...... (4认同)

Sat*_*hia 10

下面的代码有助于在地图插入顺序中显示。

<ul>
    <li *ngFor="let recipient of map | keyvalue: asIsOrder">
        {{recipient.key}} --> {{recipient.value}}
    </li>
</ul>
Run Code Online (Sandbox Code Playgroud)

.ts 文件中添加以下代码。

asIsOrder(a, b) {
    return 1;
}
Run Code Online (Sandbox Code Playgroud)


Arm*_*yan 6

这是因为map.keys()返回一个迭代器.*ngFor可以使用迭代器,但是map.keys()会在每个更改检测周期调用,从而产生对数组的新引用,从而导致您看到的错误.顺便说一句,这并不总是像你传统上想到的那样错误 ; 它甚至可能不会破坏你的任何功能,但暗示你有一个似乎以疯狂的方式运行的数据模型 - 变化比变化检测器检查其值更快.

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

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


Pat*_*ith 5

keyvalue可以使用Angular\xe2\x80\x99s管道,但不幸的是它按键排序。地图已经有订单了,如果能够保留它那就太好了!

\n

我们可以定义自己的管道mapkeyvalue来保留映射中项目的顺序:

\n
import { Pipe, PipeTransform } from \'@angular/core\';\n\n// Holds a weak reference to its key (here a map), so if it is no longer referenced its value can be garbage collected.\nconst cache = new WeakMap<ReadonlyMap<any, any>, Array<{ key: any; value: any }>>();\n\n@Pipe({ name: \'mapkeyvalue\', pure: true })\nexport class MapKeyValuePipe implements PipeTransform {\n  transform<K, V>(input: ReadonlyMap<K, V>): Iterable<{ key: K; value: V }> {\n    const existing = cache.get(input);\n    if (existing !== undefined) {\n      return existing;\n    }\n\n    const iterable = Array.from(input, ([key, value]) => ({ key, value }));\n    cache.set(input, iterable);\n    return iterable;\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

它可以像这样使用:

\n
<mat-select>\n  <mat-option *ngFor="let choice of choicesMap | mapkeyvalue" [value]="choice.key">\n    {{ choice.value }}\n  </mat-option>\n</mat-select>\n
Run Code Online (Sandbox Code Playgroud)\n