# The Angular Standalone Component Gotcha I Didn’t See Coming

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:

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

And in the template:

```bash
<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:

```bash
<li *ngFor="let item of ['a', 'b', 'c']">{{ item }}</li>
```

Still nothing.

Then I tried this:

```bash
<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:

```javascript
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:

```javascript
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:

```javascript
<ul>
  @for (option of filterOptions; track $index) {
    <li>{{ option }}</li>
  }
</ul>
```

or conditionally:

```javascript
@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.
