Question
How can I fix the Angular template error below when trying to render a list of conference talks?
import { bootstrap, Component } from 'angular2/angular2';
@Component({
selector: 'conf-talks',
template: `<div *ngFor="talk of talks">
{{ talk.title }} by {{ talk.speaker }}
<p>{{ talk.description }}</p>
</div>`
})
class ConfTalks {
talks = [
{ title: 't1', speaker: 'Brian', description: 'talk 1' },
{ title: 't2', speaker: 'Julie', description: 'talk 2' }
];
}
@Component({
selector: 'my-app',
directives: [ConfTalks],
template: '<conf-talks></conf-talks>'
})
class App {}
bootstrap(App, []);
Angular reports:
EXCEPTION: Template parse errors:
Can't bind to 'ngFor' since it isn't a known native property
What is incorrect about the *ngFor usage, and what must be imported or configured for Angular to recognize it?
Short Answer
*ngFor is Angular’s structural directive for repeating an element once per item in a collection. You must use its microsyntax correctly—normally let item of items—and make the NgFor directive available to the component. In modern Angular, standalone components import NgFor or CommonModule; NgModule-based components import CommonModule in their module.
Concept
*ngFor is not a native HTML property. It is an Angular structural directive: a feature that changes which parts of the DOM Angular creates.
The asterisk (*) is shorthand syntax. This:
<li *ngFor="let talk of talks">{{ talk.title }}</li>
is conceptually expanded by Angular into an ng-template:
<ng-template ngFor let-talk [ngForOf]="talks">
<li>{{ talk.title }}</li>
</ng-template>
The directive needs two important pieces of information:
talks: the iterable collection to loop through.talk: a local variable representing the current item.
That is why modern Angular syntax uses let talk of talks. Without let, Angular cannot interpret talk as the loop variable correctly.
Angular must also know what ngFor is. A component only has access to directives that it imports directly, or that are exported by an imported Angular module. If NgFor is unavailable, Angular may treat ngFor like an unknown property on a normal HTML element and report the “isn't a known property” error.
Mental Model
Think of *ngFor as a photocopier with a stack of records.
- The collection (
talks) is the stack. - The loop variable (
talk) is the record currently on the copier. - The HTML element is the page to copy.
For every record in talks, Angular creates one copy of the element and fills in expressions such as {{ talk.title }}.
However, the copier must be installed in the room first. Importing NgFor or CommonModule makes the *ngFor feature available to the component.
Syntax and Examples
Use let to declare the local loop variable.
<div *ngFor="let talk of talks">
<h2>{{ talk.title }}</h2>
<p>Presented by {{ talk.speaker }}</p>
<p>{{ talk.description }}</p>
</div>
In a modern standalone Angular component, import NgFor:
import { Component } from '@angular/core';
import { NgFor } from '@angular/common';
@Component({
selector: 'app-conf-talks',
standalone: true,
imports: [NgFor],
template: `
<div *ngFor="let talk of talks">
<h2>{{ talk.title }}</h2>
<p>{{ talk.speaker }}</p>
</div>
`
})
export class ConfTalksComponent {
talks = [
{ title: 't1', speaker: 'Brian', description: 'Talk 1' },
{ title: 't2', speaker: 'Julie', description: 'Talk 2' }
];
}
You can import CommonModule instead when you need several common directives and pipes:
import { CommonModule } from '@angular/common';
@Component({
standalone: true,
imports: [CommonModule],
template: `<p *ngFor="let name of names">{{ name }}</p>`
})
export class NamesComponent {
names = ['Ana', 'Mo', 'Sam'];
}
CommonModule includes common template features such as NgFor, NgIf, and common pipes.
Step by Step Execution
Consider this component:
@Component({
standalone: true,
imports: [NgFor],
template: `
<p *ngFor="let color of colors">{{ color }}</p>
`
})
export class ColorListComponent {
colors = ['red', 'green', 'blue'];
}
Angular processes it as follows:
- It creates
ColorListComponent. - It evaluates
colors, producing['red', 'green', 'blue']. NgForreceives that array through theof colorsportion.- On the first iteration, Angular sets
colorto'red'and creates<p>red</p>. - On the second iteration, it sets
colorto'green'and creates<p>green</p>. - On the third iteration, it sets
colorto'blue'and creates<p>blue</p>.
The rendered result is:
<p>red</p>
<p>green</p>
<p>blue</p>
If colors later changes, Angular updates the repeated views to match the new collection.
Real World Use Cases
*ngFor is used whenever an interface needs to display a collection of data.
- API results: render products returned by an online store API.
- Dashboard tables: show users, invoices, orders, or audit events.
- Navigation: generate menu links from a configuration array.
- Forms: render selectable categories, countries, or tags.
- Chat and activity feeds: show messages and notifications in order.
- Validation messages: display every validation error associated with a form field.
Example: rendering API-loaded products.
<article *ngFor="let product of products">
<h3>{{ product.name }}</h3>
<p>{{ product.price | currency }}</p>
</article>
Real Codebase Usage
In production applications, developers usually combine *ngFor with stable identity, filtering in component code, and empty-state handling.
Track items by a stable identifier
When a list receives updated objects from an API, tracking by ID helps Angular preserve existing DOM elements.
trackByTalkId(index: number, talk: { id: number }): number {
return talk.id;
}
<article *ngFor="let talk of talks; trackBy: trackByTalkId">
{{ talk.title }}
</article>
Handle empty collections
<ul *ngIf="talks.length > 0; else noTalks">
<li *ngFor="let talk of talks">{{ talk.title }}</li>
</ul>
<ng-template #noTalks>
<p>No talks are available yet.</p>
</ng-template>
Keep template expressions simple
Avoid putting expensive filtering or sorting logic directly in the template. Prepare the displayed list in the component, a computed signal, or an observable pipeline instead.
visibleTalks = this.talks.filter(talk => talk.isPublished);
Then loop over visibleTalks rather than repeatedly calling a filtering method from the template.
Common Mistakes
Forgetting let
Broken modern syntax:
<div *ngFor="talk of talks">
Correct syntax:
<div *ngFor="let talk of talks">
let talk declares a local variable for each item.
Not importing NgFor or CommonModule
A standalone component must explicitly make the directive available:
imports: [NgFor]
or:
imports: [CommonModule]
For an NgModule-based application, import CommonModule into the feature module that declares the component. BrowserModule provides common directives for the root application module, but feature modules should use CommonModule.
Using in instead of of
Broken:
<li *ngFor="let talk in talks">{{ talk.title }}</li>
Correct:
<li *ngFor="let talk of talks">{{ talk.title }}</li>
Angular uses of; JavaScript’s for...in has different behavior and is not NgFor syntax.
Putting two structural directives on one element
Broken:
<li *ngFor="let talk of talks" *ngIf="talk.featured">
{{ talk.title }}
</li>
Use a wrapping container instead:
<ng-container *ngFor="let talk of talks">
<li *ngIf="talk.featured">{{ talk.title }}</li>
</ng-container>
Confusing older Angular syntax with current syntax
Very early Angular 2 releases used syntax such as #talk for a template variable. Current Angular uses let talk. Follow the documentation for the Angular version installed in your project; do not mix examples from old Angular 2 previews with current Angular code.
Comparisons
| Feature | Purpose | Example | Notes |
|---|---|---|---|
*ngFor | Repeats an element for every item | *ngFor="let item of items" | Use for arrays and other iterables. |
*ngIf | Includes or removes an element based on a condition | *ngIf="isLoggedIn" | Use for conditional display. |
@for | Modern built-in Angular control flow for repetition | @for (item of items; track item.id) { ... } | Available in newer Angular versions; it is an alternative to *ngFor. |
JavaScript for...of | Loops in TypeScript or JavaScript code | for (const item of items) {} | Runs in component code, not templates. |
JavaScript for...in | Iterates enumerable object keys | for (const key in object) {} | Not appropriate for Angular *ngFor syntax. |
In newer Angular versions, @for can be a clear option:
@for (talk of talks; track talk.id) {
<article>{{ talk.title }}</article>
} @empty {
<p>No talks found.</p>
}
Use the syntax that matches your project’s Angular version and team conventions.
Cheat Sheet
<!-- Current *ngFor syntax -->
<li *ngFor="let item of items">{{ item }}</li>
<!-- Index and first-item state -->
<li *ngFor="let item of items; let i = index; let first = first">
{{ i }}: {{ item }}
</li>
<!-- Track by ID -->
<li *ngFor="let item of items; trackBy: trackById">
{{ item.name }}
</li>
// Standalone component
import { NgFor } from '@angular/common';
@Component({
standalone: true,
imports: [NgFor]
})
// Or import a group of common template tools
import { CommonModule } from '@angular/common';
@Component({
standalone: true,
imports: [CommonModule]
})
- Use
let item of items, notitem of items. - Use
of, notin. NgFormust be available in the component’s template scope.- A structural directive uses
*shorthand and normally occupies one host element. - Use
trackByfor dynamic lists with stable IDs.
FAQ
Why does Angular say ngFor is not a known property?
Angular does not have the NgFor directive in that component’s template scope, or the *ngFor microsyntax is malformed. Import NgFor or CommonModule and use let item of items.
Do I need to import NgFor in every standalone component?
Yes, unless you import CommonModule, another shared import that exports it, or use modern @for control flow instead. Standalone components explicitly declare their template dependencies.
Should I import NgFor or CommonModule?
Import NgFor when that is the only common directive you need. Import CommonModule when the component also needs features such as NgIf, NgSwitch, or common pipes.
What does let talk of talks mean?
It means: for every value in talks, create a local template variable named talk that refers to the current value.
Can *ngFor iterate over an object?
*ngFor is designed for iterables such as arrays. For a plain object, first convert its keys or entries into an array in component code, for example with Object.entries(object).
How do I get the current index in *ngFor?
Declare it in the microsyntax:
<div *ngFor="let talk of talks; let i = index">
{{ i }} - {{ talk.title }}
</div>
Why should I use trackBy?
For lists updated with new object instances, trackBy lets Angular identify items by a stable value such as an ID. This can reduce unnecessary DOM recreation and preserve state in repeated elements.
Mini Project
Description
Build a small conference-talk list that renders data with *ngFor, shows the item number, and displays a useful message when there are no talks. This mirrors a common API-driven UI: a component receives a collection and turns each record into visible content.
Goal
Create a standalone Angular component that safely displays a list of conference talks using NgFor and NgIf.
Requirements
Requirement 1
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.