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:
item.keywill bekey1, thenkey2item.valuewill 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
- 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.keyiskey1item.valueisapple
- On the second iteration:
item.keyiskey2item.valueisbanana
- 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:
- Outer loop gets
key1and its array. - Inner loop walks through the array items:
{ key11: 'value11' }{ key12: 'value12' }
- Innermost loop converts each object into key-value entries.
- 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 }
- 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>
This lets the UI adapt automatically if new settings are added later.
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:
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:
<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:
itemis 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
| 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 |
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
| AngularJS | Angular |
|---|---|
ng-repeat="(key, value) in obj" | `*ngFor="let item of obj |
| Template-driven object iteration syntax | Uses a pipe to convert object entries |
| Older framework syntax | Modern Angular structural directive syntax |
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
item.valuefor 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.
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
@Directive vs @Component in Angular: Differences, Use Cases, and When to Use Each
Learn the difference between @Directive and @Component in Angular, including use cases, examples, and when to choose each.
Accessing Input Value from EventTarget in TypeScript
Learn why EventTarget has no value property in TypeScript and safely read values from HTML input events in Angular applications.
Angular (change) vs (ngModelChange): What’s the Difference?
Learn the difference between Angular (change) and (ngModelChange), when each fires, and which one to use in forms and inputs.