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

I'm new to angular 5 and trying to iterate over a map containing another map in typescript. As iterating below this kind of map in angular, below is the code for the component:

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); } } 

and its html template:

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

runtime error

+53
source share
4 answers

For Angular 6. 1+, you can use the default keyvalue ( keyvalue and raise as well ):

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

WORKING DEMO


For previous version:

One simple solution to this problem is to convert the map to an array: Array.from

Component Side:

 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()); } 

Template Side:

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

WORKING DEMO

+94
source

If you are using Angular 6.1 or later, the most convenient way is to use 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']]); } 
+27
source

Edit

For angular 6.1 and later use KeyValuePipe as suggested by Londeren.

For angular 6.0 and older

To make things easier, you can create a pipe.

 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"> 

How clean it is, it will not work every time changes are detected, but only if the map variable is changed

Stackblitz demo

+19
source

This is because map.keys() returns an iterator. *ngFor can work with iterators, but map.keys() will be called in every change detection cycle, thereby creating a new array reference, resulting in an error. By the way, this is not always a mistake that you would normally think of; it may not even violate your functionality, but it assumes that you have a data model that seems to behave insanely - changes faster than the change detector checks its value.

If you do not want to convert the map to an array in your component, you can use the channel suggested in the comments. There is no other workaround as it seems.

PS This error will not be displayed in production mode, since it rather resembles a very strict warning, rather than an actual error, but, nevertheless, it is not a good idea to leave it.

+6
source

Source: https://habr.com/ru/post/1274612/


All Articles