Fellow developers,
We all know that scenario where nothing seems broken — no errors, no warnings — yet the interface just... refuses to behave as expected.
That is exactly how this saga kicked off.
However, let me give you a bit of context beforehand...
🧳 Coming Back to Angular After Half a Decade
Only recently did I return to Angular, following nearly five years of absence.
Everything I once knew instinctively?
Either vanished or transformed.
Now we have standalone: true. Modules are no longer mandatory. Components act more like self-contained pieces.
It’s still Angular — yet somehow not.
Thus, when I set out to create a simple standalone navbar component featuring a dropdown filter, I believed I was ready to jump straight in.
After all, what could possibly be tough about *ngFor?
As it turned out, quite a bit — especially when you're working without full awareness.
🚧 The Configuration
My task involved building a home-navbar component — a straightforward filter offering options like “Latest”, “Trending”, and “Following”.
Within home-navbar.component.ts, this is what I assembled:
filterOptions = ['latest', 'trending', 'following'];
And in the template:
<ul>
<li *ngFor="let option of filterOptions">{{ option }}</li>
</ul>
What a vision of simplicity. What a sight to behold.
And yet... it completely bypasses all logic.
😵💫 Chasing an Invisible Glitch
Zero errors raised. Zero warnings emitted. All you get is a bare <ul>.
It’s the kind of failure where Angular stays silent — brushing it off without a hint.
My debugging steps went like this:
✅ I called
console.log(filterOptions)— the data was populated.✅ I wrote
{{ filterOptions }}inside the template — it output perfectly.❌
*ngFor— utterly ignored, as if it had never been added.
Then I even swapped it out for:
<li *ngFor="let item of ['a', 'b', 'c']">{{ item }}</li>
Still nothing.
Then I tried this:
<div *ngIf="true">Hello ngIf</div>
And when that failed to appear on screen...
I completely lost it.
💡 The Realization
After a moment of panic, I turned to the documentation. And then it clicked:
Since this is a standalone component, it gets no inherited imports—not even Angular’s core directives.
That’s when I finally saw what I had been overlooking the whole time:
import { CommonModule } from '@angular/common';
@Component({
standalone: true,
...
imports: [CommonModule, ...] // ← The missing piece
})
That single line was the culprit behind every silent failure in the codebase.
🔍 Why It Happens
Here's how Angular handles this:
For regular components within an
NgModule, a singleCommonModuleimport provides directives to every declared component.However, standalone components are entirely on their own.
In that case, you have to add
CommonModuleto your imports manually — otherwise*ngIf,*ngFor,| date,| currency, and similar features just won’t be available.
🤦 Lesson from the Drama
My attention was so locked on crafting the UI and getting features to work that I never paused to consider a simpler question:
"Hold on, what actually supplies structural directives?"
That moment served as a powerful wake-up call:
Even for those with years of experience, it's all too easy to slip into routine and miss the details that carry real weight.
Honestly, I wasn't really practicing Angular — I was going through the motions.
And Angular itself? It has moved on.
✅ The Fix
Adding this single import brought everything back into order:
imports: [CommonModule]
After that addition, *ngFor started functioning again. *ngIf also resumed working. Everything was back to normal.
✨ Update: Angular 17+ Alternative Without CommonModule
As of Angular 17, a more streamlined approach exists for managing loops that requires no CommonModule import whatsoever.
✅ The templates now support the native @for and @if control flow directly.
Here's an example:
<ul>
@for (option of filterOptions; track $index) {
<li>{{ option }}</li>
}
</ul>
or conditionally:
@if (filterOptions.length > 0) {
<p>We have {{ filterOptions.length }} options!</p>
}
🏆 Best Practice
Angular 16 or earlier:
Go withCommonModule.Angular 17 or later:
Opt for the@forand@ifsyntax.When older Angular versions are a requirement, keep using
*ngForand*ngIfalong with CommonModule.
🔑 Takeaways
Standalone components carry standalone duties.
No dependency is brought in automatically — you decide precisely what gets imported.Missing CommonModule?
Then zero*ngFor, zero*ngIf, zero pipes — and not a single error message.
Angular passes over them in silence, which leaves you puzzled.Re-entering the framework after a long pause?
Don't expect the old rules to hold.
Even well-known features shift — usually in subtle, quiet increments.Minor details lead to major, quiet failures.
Pause and double-check the fundamentals every time — that's where issues usually appear first.Extra perk for Angular 17+:
The updated@forand@ifsyntax trims boilerplate further — no CommonModule required whatsoever!
🗯️ Have You Had “Silent Failures” Too?
Have you burned hours hunting down a bug that turned out to be just one absent import?
Or watched a component misbehave because of an unspoken Angular constraint?
Tell us about it.
Let’s embrace the awkward stage of learning and relearning.
After all, it’s not just about mastering Angular.
It’s about knowing which details deserve a second look.
