Question

How to Iterate Over Object Keys and Values with *ngFor in Angular

typescriptangularobject

Question

I am confused about how to access the keys and values of an object in Angular while using *ngFor to iterate over it.

In AngularJS 1.x, there was syntax like this:

<div ng-repeat="(key, value) in demo">
  {{ key }} - {{ value }}
</div>

I am not sure how to do the equivalent in Angular.

I tried something like this:

<ul>
  <li *ngFor="let key of demo">{{ key }}</li>
</ul>
demo = {
  key1: [{ key11: 'value11' }, { key12: 'value12' }],
  key2: [{ key21: 'value21' }, { key22: 'value22' }]
};

How can I get key1 and key2 dynamically using *ngFor?

Do I need to use a pipe for this? If so, is there a built-in pipe in Angular for iterating over object keys and values?

Short Answer

By the end of this page, you will understand why *ngFor works directly with arrays but not plain objects, and how Angular lets you iterate over object properties using the built-in keyvalue pipe. You will also learn how to access both the key and the value, display nested data, avoid common mistakes, and choose between looping over objects and converting data into arrays.

Concept

*ngFor is designed to loop over iterables, most commonly arrays. A plain JavaScript object is not an iterable in the same way an array is.

For example, this works:

items = ['a', 'b', 'c'];
<li *ngFor="let item of items">{{ item }}</li>

But this does not work the same way for a plain object:

demo = {
  key1: 'value1',
  key2: 'value2'
};

That is because demo is a key-value object, not an array.

In Angular, the usual solution is to use the built-in keyvalue pipe, which converts an object into an array of entries. Each entry has:

  • key
  • value

So Angular can then loop through those entries with *ngFor.

This matters in real programming because many APIs and configuration objects return data as objects rather than arrays. If you know how to iterate through object properties safely, you can render dynamic menus, settings panels, grouped data, and API responses more easily.

Mental Model

Think of an array as a numbered list:

  • position 0
  • position 1
  • position 2

*ngFor naturally walks through that list one item at a time.

Now think of an object as a labeled set of drawers:

  • drawer key1
  • drawer key2

Each drawer has a label (the key) and something inside it (the value).

*ngFor cannot directly walk through drawers unless Angular first turns them into a list. The keyvalue pipe does exactly that: it turns the drawers into a list of { key, value } pairs so Angular can loop over them.

Take Quiz

Syntax and Examples

Basic syntax with keyvalue

<li *ngFor="let item of demo | keyvalue">
  {{ item.key }}: {{ item.value }}
</li>

Example with your object

demo = {
  key1: [{ key11: 'value11' }, { key12: 'value12' }],
  key2: [{ key21: 'value21' }, { key22: 'value22' }]
};
<ul>
  <li *ngFor="let item of demo | keyvalue">
    <strong>{{ item.key }}</strong>
    <pre>{{ item.value | json }}</pre>
  </li>
</ul>

What this gives you

For each property in demo:

  • item.key will be key1, then key2
  • item.value will be the corresponding array

Nested example

Because each value is an array, you can loop again inside it:

<div *ngFor="let group of demo | keyvalue">
  <h3>{{ group.key }}</h3>

  <ul>
    <li *ngFor="let obj of group.value">
      {{ obj | json }}
    </li>
  </ul>
</div>

Showing inner object properties

If the nested objects also need key-value iteration:

<div *ngFor="let group of demo | keyvalue">
  <h3>{{ group.key }}</h3>

  <div *ngFor="let obj of group.value">
    <div *ngFor="let entry of obj | keyvalue">
      {{ entry.key }}: {{ entry.value }}
    </div>
  </div>
</div>

This is useful when object shapes are dynamic and you do not know the property names in advance.

Step by Step Execution

Consider this data:

demo = {
  key1: 'apple',
  key2: 'banana'
};

And this template:

<ul>
  <li *ngFor="let item of demo | keyvalue">
    {{ item.key }} = {{ item.value }}
  </li>
</ul>

Step by step

  1. Angular evaluates demo.
  2. The keyvalue pipe converts it into something like:
[
  { key: 'key1', value: 'apple' },
  { key: 'key2', value: 'banana' }
]
  1. *ngFor loops over that array.
  2. On the first iteration:
    • item.key is key1
    • item.value is apple
  3. On the second iteration:
    • item.key is key2
    • item.value is banana
  4. Angular renders:
key1 = apple
key2 = banana

Step by step with your nested structure

demo = {
  key1: [{ key11: 'value11' }, { key12: 'value12' }],
  key2: [{ key21: 'value21' }, { key22: 'value22' }]
};
<div *ngFor="let group of demo | keyvalue">
  <h3>{{ group.key }}</h3>

  <div *ngFor="let obj of group.value">
    <div *ngFor="let entry of obj | keyvalue">
      {{ entry.key }} = {{ entry.value }}
    </div>
  </div>
</div>

Execution flow:

  1. Outer loop gets key1 and its array.
  2. Inner loop walks through the array items:
    • { key11: 'value11' }
    • { key12: 'value12' }
  3. Innermost loop converts each object into key-value entries.
  4. The same process repeats for key2.

Real World Use Cases

Iterating over object keys and values is common in Angular applications when data is not stored as a simple array.

Common scenarios

  • Settings pages
    • Example: an object of feature flags like { darkMode: true, notifications: false }
  • Grouped API responses
    • Example: products grouped by category name
  • Dynamic forms
    • Example: field names and validation rules stored in an object
  • Translation dictionaries
    • Example: language keys like { welcome: 'Hello', logout: 'Sign out' }
  • Dashboard widgets
    • Example: metrics returned as { users: 120, sales: 45, revenue: 9000 }

Example: rendering app settings

settings = {
  darkMode: true,
  emailAlerts: false,
  autoSave: true
};
<div *ngFor="let setting of settings | keyvalue">
  {{ setting.key }}: {{ setting.value }}
</div>

This lets the UI adapt automatically if new settings are added later.

Take Quiz

Real Codebase Usage

In real projects, developers often use object iteration in a few predictable ways.

1. Rendering dynamic sections

A backend may return grouped data as an object:

ordersByStatus = {
  pending: [{ id: 1 }, { id: 2 }],
  shipped: [{ id: 3 }]
};

Then the template renders each section dynamically.

2. Guarding against missing data

Developers often combine object iteration with guard clauses in the template or component.

<div *ngIf="ordersByStatus">
  <div *ngFor="let group of ordersByStatus | keyvalue">
    {{ group.key }}
  </div>
</div>

This avoids errors when data has not loaded yet.

3. Converting objects into arrays in the component

Sometimes teams prefer preparing data before it reaches the template.

entries = Object.entries(this.demo).map(([key, value]) => ({ key, value }));
<div *ngFor="let entry of entries">
  {{ entry.key }}
</div>

This can make templates simpler.

4. Nested rendering

Large Angular apps often render grouped navigation, filters, or summaries using nested loops over object values.

5. Validation and fallback handling

If data structure may vary, developers often check values before rendering:

<div *ngFor="let item of data | keyvalue">
  <span *ngIf="item.value != null">{{ item.key }}: {{ item.value }}</span>
</div>

This helps avoid blank or broken output.

Common Mistakes

1. Trying to loop over an object directly

Broken example:

<li *ngFor="let key of demo">{{ key }}</li>

Why it fails:

  • demo is an object, not an array
  • *ngFor expects something iterable

Fix:

<li *ngFor="let item of demo | keyvalue">
  {{ item.key }}
</li>

2. Using old AngularJS syntax in Angular

Broken example:

<div ng-repeat="(key, value) in demo"></div>

Why it fails:

  • ng-repeat is AngularJS syntax
  • Angular uses *ngFor

Fix:

<div *ngFor="let item of demo | keyvalue">
  {{ item.key }} - {{ item.value }}
</div>

3. Forgetting let in *ngFor

Broken example:

<div *ngFor="item of demo | keyvalue">
  {{ item.key }}
</div>

Fix:

<div *ngFor="let item of demo | keyvalue">
  {{ item.key }}
</div>

4. Expecting item itself to be the key

Broken expectation:

<div *ngFor="let item of demo | keyvalue">
  {{ item }}
</div>

Why it is confusing:

  • item is an object like { key: 'key1', value: ... }

Fix:

<div *ngFor="let item of demo | keyvalue">
  {{ item.key }}
</div>

5. Not understanding nested structures

Your values are arrays, so printing item.value directly may not be very readable.

Example:

<div *ngFor="let item of demo | keyvalue">
  {{ item.key }}: {{ item.value }}
</div>

Better:

<div *ngFor="let item of demo | keyvalue">
  <h3>{{ item.key }}</h3>
  <div *ngFor="let child of item.value">
    {{ child | json }}
  </div>
</div>

6. Assuming object order is always ideal

When displaying objects, ordering may matter. If your UI depends on a specific order, consider converting the object to an array yourself and sorting it in the component.

Comparisons

ApproachBest forProsCons
*ngFor over an arrayLists of itemsSimple and directDoes not work directly with plain objects
*ngFor with keyvalue pipePlain objects in templatesBuilt-in and convenientTemplate can become more complex with nested data
Object.keys() in componentCustom processingFull control over order and structureMore code in component
Object.entries() in componentNeed both keys and valuesEasy to transform into arrayRequires preparation before template

keyvalue pipe vs converting in the component

Use keyvalue pipe when:

  • you need a quick template solution
  • the object is simple
  • you want less component code

Convert in the component when:

  • you need custom sorting
  • you want a cleaner template
  • the data needs preprocessing

AngularJS vs Angular

AngularJSAngular
ng-repeat="(key, value) in obj"`*ngFor="let item of obj
Template-driven object iteration syntaxUses a pipe to convert object entries
Older framework syntaxModern Angular structural directive syntax
Take Quiz

Cheat Sheet

Quick syntax

Loop over object entries:

<div *ngFor="let item of myObject | keyvalue">
  {{ item.key }}: {{ item.value }}
</div>

Entry shape

Each item has:

{
  key: string,
  value: any
}

Nested object loop

<div *ngFor="let group of demo | keyvalue">
  {{ group.key }}
  <div *ngFor="let child of group.value">
    {{ child | json }}
  </div>
</div>

Remember

  • *ngFor works naturally with arrays
  • plain objects need keyvalue
  • use item.key for the property name
  • use item.value for the property value
  • nested arrays may need another *ngFor
  • nested objects may need another | keyvalue

Common fix

Wrong:

<li *ngFor="let x of myObject">...</li>

Right:

<li *ngFor="let x of myObject | keyvalue">...</li>

Alternative in component

entries = Object.entries(myObject).map(([key, value]) => ({ key, value }));

FAQ

How do I get object keys in Angular template?

Use the built-in keyvalue pipe:

<div *ngFor="let item of obj | keyvalue">
  {{ item.key }}
</div>

How do I get both key and value with *ngFor?

Use item.key and item.value after applying the keyvalue pipe.

Can *ngFor iterate over a plain JavaScript object directly?

No. It is meant for iterables such as arrays. For objects, use keyvalue or convert the object into an array in the component.

Is there a built-in pipe for object iteration in Angular?

Yes. Angular provides the keyvalue pipe.

What if the object value is an array?

You can use another *ngFor inside the first one to loop through that array.

Should I use keyvalue in the template or Object.entries() in the component?

Use keyvalue for simple cases. Use Object.entries() in the component when you need custom sorting, transformation, or a cleaner template.

Why does my old ng-repeat code not work in Angular?

Because ng-repeat belongs to AngularJS. In Angular, the equivalent directive is *ngFor, and object iteration is usually done with keyvalue.

Take Quiz

Mini Project

Description

Build a small Angular view that displays grouped data from an object. This demonstrates how to loop through object keys with the keyvalue pipe and then loop through nested arrays inside each key. It reflects a common real-world pattern such as categories and products, departments and employees, or statuses and tasks.

Goal

Create a template that dynamically renders object keys as section headings and shows the related nested items under each heading.

Requirements

[ "Create an object with at least two top-level keys.", "Use *ngFor with the keyvalue pipe to display each top-level key.", "Render the value of each key as a nested list.", "Use a second loop if the value is an array.", "Show both dynamic keys and dynamic values in the UI." ]

Take Quiz

Keep learning

Related questions

View more