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}} |
对于Angular 6.1,您可以使用默认管道
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"> |
就其本身而言,它不会在每次更改检测时都被触发,只有在对
Stackblitz演示
这是因为
如果您不想将映射转换为组件中的数组,则可以使用注释中建议的管道。似乎没有其他解决方法。
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的
我们可以定义自己的管道
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> |