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:

*ngFor="let option of filterOptions">{{ option }}

So clean. So elegant.

So... not working.


😵‍💫 Debugging the Invisible

No errors. No warnings. Just an empty

    .

    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:

    *ngFor="let item of ['a', 'b', 'c']">{{ item }}

    Still nothing.

    Then I tried this:

    *ngIf="true">Hello ngIf

    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.