๐Ÿณ IntuitiveFE
Login
โ† All concepts

Angular Components & Decorators

โฑ๏ธ ~5-minute bite ยท solve the sandbox to master

0%lesson
๐Ÿง’

5-Year-Old Metaphor

โ€” The physical, real-world picture. No jargon.

๐Ÿท๏ธ Decorator = blueprint label stapled to a class. The class is plain TypeScript. The decorator transforms it into an Angular component at compile time โ€” like a shipping label that says โ€œfragile: handle with care.โ€ It doesn't change what's inside the box.

The compilation pipeline

1. TypeScript

@Component({...}) class MyComp โ€” plain class with metadata attached

2. Angular Compiler

Reads metadata statically, generates factory functions and change detection instructions

3. Runtime

Factory instantiates the class, wires up DI, connects template to the component instance

Lifecycle hooks โ€” guaranteed order

constructorโ†’ngOnChangesโ†’ngOnInitโ†’ngDoCheckโ†’ngAfterContentInitโ†’ngAfterContentCheckedโ†’ngAfterViewInitโ†’ngAfterViewCheckedโ†’ngOnDestroy

ngOnChanges fires before ngOnInit and again whenever an @Input() changes. ngAfterViewInit is the first safe place to access @ViewChild queries. ngOnDestroy is where you unsubscribe and cancel timers.

๐ŸŽ›๏ธ

Interactive Sandbox

โ€” Move something, see it react instantly.

Pattern

What it does

The @Component decorator transforms a plain TypeScript class into an Angular component. It attaches metadata the compiler reads to wire up templates, styles, DI, and change detection.

@Component anatomy โ€” Angular 17+ example
js
1import { Component, ChangeDetectionStrategy } from '@angular/core';
2ย 
3@Component({
4 selector: 'app-card', // CSS selector โ€” how you use it in templates
5 standalone: true, // no NgModule needed (Angular 14+)
6 imports: [CommonModule], // standalone: true requires this instead of NgModule
7 templateUrl: './card.component.html',
8 styleUrl: './card.component.scss',
9 changeDetection: ChangeDetectionStrategy.OnPush, // opt-in to efficient CD
10})
11export class CardComponent {
12 // Angular DI โ€” request services via constructor params
13 constructor(private readonly logger: LoggerService) {}
14}
Gotcha: Forgetting standalone: true and then importing the component without NgModule โ€” Angular will throw 'Component is not included in any module'. Either add it to an NgModule's declarations or mark it standalone.
Insight: The decorator runs at class definition time (not at instantiation). Angular's compiler reads the metadata statically to generate factory code. At runtime, the decorator itself is a no-op โ€” all the magic was done ahead of time.
Explored 1/5:๐Ÿ—๏ธ๐Ÿ“ก๐Ÿ‘๏ธ๐Ÿ“ฆ๐ŸŽฏ
๐ŸŽฏ

Challenge

Explore all 5 @Component patterns. Cover: anatomy, inputs/outputs, ViewChild, content projection, and host bindings.

Try it
๐ŸŽฏ

Why Should I Care?

โ€” The exact interview question + the bug it kills.

Interview questions

Q: What does @Component do that a plain class can't?

@Component attaches metadata that Angular reads to: register the component in the DI tree, compile the template into change-detection instructions, scope styles with ViewEncapsulation, and expose the component via its selector. A plain class is invisible to Angular โ€” it can't be used in templates, can't receive DI, and has no lifecycle hooks.

Q: What's the difference between @Input() and input() signal?

@Input() is push-based โ€” Angular writes to the property and you implement ngOnChanges to react. input() returns an InputSignal โ€” a reactive primitive you read with (). Signals compose with computed() and effect(), enabling fine-grained reactivity without ngOnChanges or manual subscriptions. Signal inputs also support required and transform at the type level.

Q: When should you use standalone: true?

For all new Angular 14+ components. Standalone components declare their own imports, which means better tree-shaking (only what's actually used gets bundled), simpler mental model (no hunting through NgModule.declarations), and easier lazy loading. NgModule-based components still work and are common in existing codebases โ€” understand both.

๐Ÿ”ฌ

The Deep Dive

โ€” Spec refs, engine internals, the minutiae.

ChangeDetection: OnPush โ€” how it works

With the default strategy, Angular checks every component in the tree after every async event (click, timer, HTTP). With OnPush, Angular only checks a component when: (1) an @Input reference changes (shallow equality), (2) an event fires inside the component, (3) an async pipe bound in the template emits, or (4) ChangeDetectorRef.markForCheck() is called explicitly. OnPush can reduce CD work by 90%+ in large trees.

js
1// OnPush + async pipe โ€” zero manual subscriptions needed
2@Component({
3 changeDetection: ChangeDetectionStrategy.OnPush,
4 template: `
5 <div *ngIf="data$ | async as data">{{ data.name }}</div>
6 `,
7})
8export class ListComponent {
9 data$ = this.service.getData(); // Observable โ€” async pipe handles subscribe/unsubscribe
10 constructor(private service: DataService) {}
11}

@Component metadata fields โ€” full reference

FieldTypeNotes
selectorstringRequired. CSS selector for this component.
templatestringInline HTML. Mutually exclusive with templateUrl.
templateUrlstringPath to .html file. Processed at compile time.
stylesstring[]Inline CSS strings. Scoped by default.
styleUrlstringAngular 17+. Single style file path.
standalonebooleantrue skips NgModule requirement.
importsType[]Required for standalone. Consumed directives/pipes.
changeDetectionenumDefault or OnPush.
providersProvider[]Component-tree scoped services.
encapsulationenumEmulated (default), None, ShadowDom.
hostobjectHost element bindings/listeners map.
animationsany[]Angular animation triggers.
preserveWhitespacesbooleanfalse (default) strips template whitespace.

ViewEncapsulation modes

Emulated (default)

Angular adds unique attributes like _ngcontent-abc to both the template and the style selectors. Styles are scoped without Shadow DOM โ€” works in all browsers.

ShadowDom

Uses native Shadow DOM. True style isolation. Slots for content projection. Not all third-party libs support it.

None

No encapsulation. Styles leak globally. Useful for theming components or overriding third-party styles.

๐ŸŽค

Interview Questions

โ€” Real questions from real interviews โ€” with answers.

Compile-time: generates factory code. Runtime: the decorator itself is a no-op.

@Input() is push-based (Angular writes to property); input() returns a reactive InputSignal read with ().

host: {} is statically analyzable โ€” the compiler can read it without evaluating decorators at runtime.

static: true resolves the query in ngOnInit but breaks if the element is inside *ngIf or *ngFor.

select uses CSS selector syntax to route projected content into named slots.

Emulated (default) adds unique attributes; ShadowDom uses native isolation; None leaks styles globally.

๐ŸŽฎ

Memory Game

โ€” Quick quiz โ€” lock the concept in long-term memory.
1/4

When does ngAfterViewChecked fire?