Javascript

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

27 September 2026 · 7 min read

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

Building dynamic and data-rich Angular applications often involves working with complex data structures. One common scenario is needing to iterate using ngFor loop Map containing key as string and values as map iteration. This can seem daunting at first, as Angular’s ngFor directive doesn’t directly support iterating over a Map object in the same way it handles arrays. However, with the powerful keyvalue pipe, you can effectively navigate and display data from deeply nested Map structures, transforming your application’s ability to render sophisticated data models. This guide will demystify the process, providing clear, actionable steps to help you master nested Map iteration within your Angular templates, ensuring your application remains robust and responsive.

Understanding Angular’s ngFor and TypeScript Maps

Angular’s ngFor structural directive is a cornerstone of dynamic templating, allowing developers to repeat a block of HTML for each item in a collection. Traditionally, ngFor excels with arrays, easily iterating through elements like ngFor=“let item of items”. However, when faced with a JavaScript/TypeScript Map object, which stores key-value pairs, a different approach is required. A Map maintains insertion order and allows any value (objects or primitive values) as either a key or a value, making it incredibly flexible for various data organization needs.

Unlike plain objects, Map objects are inherently iterable, meaning you can loop through them using methods like Map.prototype.entries(), Map.prototype.keys(), or Map.prototype.values() in vanilla JavaScript. For instance, for (const [key, value] of myMap) { … } works perfectly in TypeScript. However, Angular templates operate differently. Directly binding ngFor=“let entry of myMap” won’t work as expected because ngFor needs an iterable object that it understands how to deconstruct into individual items for rendering. This is where Angular provides a specialized tool to bridge the gap between Map objects and template iteration.

The keyvalue pipe is specifically designed to convert a Map or an object into an array of key-value pair objects, each containing key and value properties. This transformation makes the data readily consumable by ngFor. For example, a Map like new Map([[‘a’, 1], [‘b’, 2]]) would be converted into [{ key: ‘a’, value: 1 }, { key: ‘b’, value: 2 }]. This intermediate array is what ngFor then iterates over, providing access to both the original key and its corresponding value within the template. This mechanism is crucial when you need to display both the identifier (key) and its associated data (value) from your Map in your UI.

The Challenge of Nested Map Iteration

When your data structure evolves to a Map where the values themselves are other Map objects (e.g., Map>), the iteration process becomes a two-tiered challenge. The outer Map holds categories or primary identifiers, and each of its values is another Map containing more granular data. This structure is common in scenarios like organizing products by category, users by role, or localized content by language, where each top-level key points to a collection of related items.

The primary hurdle is that ngFor needs to be applied twice: once for the outer Map and then again for each inner Map. Each application of ngFor requires the data to be in an iterable format, which means leveraging the keyvalue pipe at both levels. Failing to apply the pipe correctly at either stage will result in Angular template errors, as the directive won’t know how to interpret the Map object directly. The beauty of the keyvalue pipe lies in its ability to flatten each Map into an array of objects, making it consistently iterable for ngFor regardless of its nesting level.

Consider a scenario where you have a Map of departments, and each department’s value is another Map of employees within that department. The outer Map might have keys like “Sales” and “Marketing”, and their values would be Maps containing employee IDs as keys and employee details as values. To display this hierarchical data effectively, you’ll need to first iterate through the departments, and for each department, iterate through its employees. This nested iteration pattern, while initially complex, is incredibly powerful for rendering structured data in a user-friendly manner.

Infographic: Iterating Nested Maps
Step-by-Step Guide: Iterating a Map of Maps with ngFor ------------------------------------------------------

To effectively iterate over a Map> in Angular, we’ll break it down into manageable steps, focusing on both the component’s data preparation and the template’s rendering logic. This approach ensures clarity and maintainability for complex data binding scenarios.

Example Data Structure in your Component (TypeScript):

import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-nested-map-iteration', templateUrl: './nested-map-iteration.component.html', styleUrls: ['./nested-map-iteration.component.css'] }) export class NestedMapIterationComponent implements OnInit { // Our main Map where keys are strings and values are other Maps public categories: Map<string, Map<string, { name: string; price: number }>> = new Map(); ngOnInit(): void { // Initialize the inner maps const electronics = new Map<string, { name: string; price: number }>([ ['P001', { name: 'Laptop', price: 1200 }], ['P002', { name: 'Smartphone', price: 800 }] ]); const books = new Map<string, { name: string; price: number }>([ ['B001', { name: 'The Great Gatsby', price: 15 }], ['B002', { name: '1984', price: 12 }] ]); // Populate the outer map this.categories.set('Electronics', electronics); this.categories.set('Books', books); } // Optional: preserve original order of Map iteration // By default, keyvalue pipe orders keys alphabetically. // A custom comparator can maintain insertion order. public originalOrder = (a: any, b: any): number => { return 0; // Returning 0 means "don't change order" } } 

Steps for Template Iteration:

  1. Iterating the Outer Map

    The first step is to iterate through the main categories Map. We’ll use ngFor combined with the keyvalue pipe. The keyvalue pipe converts the Map into an array of objects, each having key and value properties. The value property, in this case, will be an inner Map.

    <div ngFor="let categoryEntry of categories | keyvalue:originalOrder"> <h3>Category: {{ categoryEntry.key }}</h3> <!-- Now, categoryEntry.value is the inner Map --> </div> 
    

    Here, categoryEntry.key will give you “Electronics” and “Books”, and categoryEntry.value will be the respective inner Map (e.g., electronics Map for the “Electronics” key). We use originalOrder to maintain the insertion order of the outer map, as the keyvalue pipe by default sorts keys alphabetically. For more details on custom comparators, refer to the Angular KeyValuePipe documentation.

  2. Iterating the Inner Map

    Inside the outer ngFor loop, we now have access to categoryEntry.value, which is itself a Map. To iterate over this inner Map, we apply the keyvalue pipe again. This allows us to access the product ID (inner key) and its details (inner value).

    <div ngFor="let categoryEntry of categories | keyvalue:originalOrder"> <h3>Category: {{ categoryEntry.key }}</h3> <ul> <li ng
    <b>Question & Answer : </b><br></br><p>I am new to angular 5 and trying to iterate the map containing another map in typescript. How to iterate below this kind of map in angular below is code for component:</p> 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); } }  <p>and its template html is :</p> <ul> <li *ngFor="let recipient of map.keys()"> {{recipient}} </li> </ul> <div>{{map.size}}</div>  <p><a href="https://i.sstatic.net/AlXEP.png" rel="noreferrer"><img alt="runtime error" src="https://i.sstatic.net/AlXEP.png"></img></a></p>
    <br></br><p><strong>For Angular 6.1+</strong> , you can use default pipe <strong><a href="https://angular.io/api/common/KeyValuePipe" rel="noreferrer">keyvalue</a></strong> ( <a href="https://stackoverflow.com/a/52532564/2349407"><strong>Do review and upvote also</strong></a> ) :</p> <ul> <li *ngFor="let recipient of map | keyvalue"> {{recipient.key}} --> {{recipient.value}} </li> </ul>  <p><strong><a href="https://stackblitz.com/edit/angular-map-keyvalue" rel="noreferrer">WORKING DEMO</a></strong></p> <hr></hr> <p><strong>For the previous version :</strong> </p> <p>One simple solution to this is convert map to array : <strong><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from" rel="noreferrer">Array.from</a></strong></p> <p>Component Side :</p> 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()); }  <p>Template Side :</p> <ul> <li *ngFor="let recipient of getKeys(map)"> {{recipient}} </li> </ul>  <p><strong><a href="https://stackblitz.com/edit/angular-map-array-from" rel="noreferrer">WORKING DEMO</a></strong></p>