The Angular Standalone Component Gotcha I Didn’t See Coming

Avinash DalviAvinash Dalvi
4 min read

Hello Devs,

You know that moment when everything looks fine — no errors, no warnings — but the UI just... doesn’t do what it’s supposed to?
That’s how this story begins.

But let me add some background first...


🧳 Returning to Angular After 5 Years

I recently jumped back into Angular after almost five years away.

Things I used to know by heart?
Gone or evolved.

There’s standalone: true now. Modules are optional. Components feel more like islands.
It’s Angular — but... different.

So when I decided to build a simple standalone navbar component with a dropdown filter, I felt ready to dive in.

After all, how hard could *ngFor be?

Turns out, harder than I expected — if you're doing it blindly.


🚧 The Setup

I was building a home-navbar component — a simple filter with values like “Latest”, “Trending”, and “Following”.

In home-navbar.component.ts, I had:

filterOptions = ['latest', 'trending', 'following'];

And in the template:

<ul>
  <li *ngFor="let option of filterOptions">{{ option }}</li>
</ul>

So clean. So elegant.
So... not working.


😵‍💫 Debugging the Invisible

No errors. No warnings. Just an empty <ul>.
The kind of bug where Angular doesn’t even bother complaining — it just shrugs.

Here’s what I tried:

  • console.log(filterOptions) — the array was there.

  • {{ filterOptions }} in the template — rendered just fine.

  • *ngFor — ignored. Like it didn’t exist.

I even replaced it with:

<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 didn’t render...
Something snapped.


💡 The Realization

After spiralling a bit, I checked the docs. Then it hit me:

This is a standalone component. It doesn’t inherit anything — not even Angular’s own core directives.

And that’s when I realised what I had missed all along:

import { CommonModule } from '@angular/common';

@Component({
  standalone: true,
  ...
  imports: [CommonModule, ...] // ← The missing piece
})

That one tiny line. That was the reason everything was failing — silently.


🔍 Why It Happens

In Angular:

  • If you're using regular components inside an NgModule, importing CommonModule once covers all declared components.

  • But if you're building standalone components, they’re completely self-contained.

  • That means you must import CommonModule yourself, or you won’t get *ngIf, *ngFor, | date, | currency, etc.


🤦 Lesson from the Drama

I was so focused on building the UI and making things work that I forgot to stop and ask:

"Wait, where do structural directives even come from?"

This was a great reminder:
Even as someone experienced, it's easy to fall into habits — and overlook small things that matter.

The truth is, I wasn't "doing Angular" — I was doing muscle memory.

And Angular? It has changed.


✅ The Fix

This one line saved my sanity:

imports: [CommonModule]

Once I added that, *ngFor worked. *ngIf worked. Everything came back to life.


✨ Update: Angular 17+ Way Without CommonModule

Starting from Angular 17, there's an even cleaner way to handle loops without needing to import CommonModule at all!

✅ You can now use the new @for and @if syntax directly in your templates.

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

  • For Angular 16 and below:
    Use CommonModule.

  • For Angular 17 and above:
    Prefer @for and @if syntax.

  • If you need to support older versions, stick to the *ngFor and *ngIf approach with CommonModule.

🔑 Takeaways

  • Standalone components mean standalone responsibilities.
    Nothing is auto-included — you explicitly manage what your component needs.

  • No CommonModule?
    Then no *ngFor, no *ngIf, no pipes — and no warnings either.
    Angular will silently skip them, leaving you scratching your head.

  • Coming back to a framework after years?
    Don't assume things work like they used to.
    Even familiar tools evolve — often in small, silent ways.

  • Tiny details break things quietly.
    Always slow down and verify the basics — they are the first place things go wrong.

  • Bonus for Angular 17+:
    The new @for and @if syntax means even less boilerplate — no CommonModule needed at all!

🗯️ Have You Had “Silent Failures” Too?

Ever spent hours debugging only to realise one import was missing?
Or a component didn’t behave because of a silent Angular rule?

Share your moment.
Let’s normalise the messy middle part of learning and relearning.

Because sometimes, it’s not about knowing Angular.
It’s about knowing what to double check.

0
Subscribe to my newsletter

Read articles from Avinash Dalvi directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Avinash Dalvi
Avinash Dalvi

13+ Years of experienced as Full Stack Developer. Also worked as architect for building solutions and product to help for automation. Solution-oriented and hands-on technical utility player. Having experience of more than 4 years of experience in E commerce and finance in each domain. Experience in having driving business automation, marketing using technology. Strong follower of open source technology. Used PHP, Python, AWS and Angular as technology stack to build product