*ngFor and *ngIf are the two most-used built-in Angular structural directives, and understanding their individual behavior — plus the one genuine restriction on combining them directly — covers the majority of conditional and repeated rendering in a typical Angular template.
Basic *ngFor
{{ product.name }}
*ngFor with the index
{{ i + 1 }}. {{ product.name }}
Basic *ngIf
Welcome back!
*ngIf with if/else
Welcome back!
Please log in
*ngIf with if/else-if/else
Loading...
Something went wrong.
Content loaded successfully.
Angular has no native *ngIf/*ngElseIf/*ngElse chain — nesting templates this way is the standard workaround for an if/else-if/else chain using only *ngIf and named ng-template references.
Why you can't put *ngFor and *ngIf on the same element
{{ product.name }}
Two structural directives can't coexist on the same element, since each one desugars to its own wrapping behind the scenes — having both would mean two conflicting template wrappers on one element.
The fix: wrap with ng-container
{{ product.name }}
Following the ng-container pattern, this splits the two directives across the container and the actual element without adding any extra wrapping DOM node to the rendered output.
Looping over a plain object's keys and values
{{ entry.key }}: {{ entry.value }}
objectEntries(obj: Record) {
return Object.entries(obj).map(([key, value]) => ({ key, value }));
}
*ngFor only iterates arrays and other genuinely iterable values natively — for a plain object, converting it to an array of key/value pairs first (via Object.entries(), as shown here, or Angular's built-in KeyValue pipe) is necessary before *ngFor can loop over it.
Using the built-in KeyValue pipe instead
{{ entry.key }}: {{ entry.value }}
The keyvalue pipe does the same object-to-array conversion directly in the template, without needing a helper method in the component class — generally the more convenient choice for a simple case, while a component method offers more control if the conversion needs custom sorting or filtering logic.
The modern alternative: Angular's built-in control flow syntax (Angular 17+)
@for (product of products; track product.id) {
{{ product.name }}
}
@if (isLoggedIn) {
Welcome back!
} @else {
Please log in
}
Newer Angular versions introduced this built-in @for/@if syntax as a more concise, JavaScript-like alternative to the *ngFor/*ngIf directives — both approaches remain valid and supported, with the newer syntax becoming increasingly common in projects built on Angular 17 and later.