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:
keyvalue
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.
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:
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
- Angular evaluates
demo. - The
keyvaluepipe converts it into something like:
[
{ key: 'key1', value: 'apple' },
{ key: 'key2', value: 'banana' }
]
*ngForloops over that array.- On the first iteration:
item.keyiskey1
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 }
- Example: an object of feature flags like
- 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' }
- Example: language keys like
- Dashboard widgets
- Example: metrics returned as
{ users: 120, sales: 45, revenue: 9000 }
- Example: metrics returned as
Example: rendering app settings
settings = {
darkMode: true,
emailAlerts: false,
autoSave: true
};
<div *ngFor="let setting of settings | keyvalue">
{{ setting.key }}: {{ setting.value }}
</div>
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).( ({ key, value }));
Common Mistakes
1. Trying to loop over an object directly
Broken example:
<li *ngFor="let key of demo">{{ key }}</li>
Why it fails:
demois an object, not an array*ngForexpects 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-repeatis AngularJS syntax- Angular uses
*ngFor
Fix:
Comparisons
| Approach | Best for | Pros | Cons |
|---|---|---|---|
*ngFor over an array | Lists of items | Simple and direct | Does not work directly with plain objects |
*ngFor with keyvalue pipe | Plain objects in templates | Built-in and convenient | Template can become more complex with nested data |
Object.keys() in component | Custom processing | Full control over order and structure | More code in component |
Object.entries() in component | Need both keys and values | Easy to transform into array | Requires preparation before template |
pipe vs converting in the component
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
*ngForworks naturally with arrays- plain objects need
keyvalue - use
item.keyfor the property name - use for the property 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?
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."
]
Keep learning
Related questions
Angular formGroup Error Explained: Fixing 'Can't bind to formGroup' in Reactive Forms
Learn why Angular shows 'Can't bind to formGroup' and how to fix it by importing ReactiveFormsModule correctly.
Fix "Element implicitly has an 'any' type" in TypeScript Object Indexing
Learn why TypeScript rejects string object indexing and how to fix it with keyof, unions, and typed object keys in React.
Fix "Property has no initializer" in Angular TypeScript Components
Learn why Angular TypeScript shows "Property has no initializer" and how to fix it using defaults, optional properties, or definite assignment.