Angular Components & Decorators
โฑ๏ธ ~5-minute bite ยท solve the sandbox to master
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
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.
| 1 | import { 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 | }) |
| 11 | export class CardComponent { |
| 12 | // Angular DI โ request services via constructor params |
| 13 | constructor(private readonly logger: LoggerService) {} |
| 14 | } |
Challenge
Explore all 5 @Component patterns. Cover: anatomy, inputs/outputs, ViewChild, content projection, and host bindings.
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.
| 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 | }) |
| 8 | export class ListComponent { |
| 9 | data$ = this.service.getData(); // Observable โ async pipe handles subscribe/unsubscribe |
| 10 | constructor(private service: DataService) {} |
| 11 | } |
@Component metadata fields โ full reference
| Field | Type | Notes |
|---|---|---|
| selector | string | Required. CSS selector for this component. |
| template | string | Inline HTML. Mutually exclusive with templateUrl. |
| templateUrl | string | Path to .html file. Processed at compile time. |
| styles | string[] | Inline CSS strings. Scoped by default. |
| styleUrl | string | Angular 17+. Single style file path. |
| standalone | boolean | true skips NgModule requirement. |
| imports | Type[] | Required for standalone. Consumed directives/pipes. |
| changeDetection | enum | Default or OnPush. |
| providers | Provider[] | Component-tree scoped services. |
| encapsulation | enum | Emulated (default), None, ShadowDom. |
| host | object | Host element bindings/listeners map. |
| animations | any[] | Angular animation triggers. |
| preserveWhitespaces | boolean | false (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.When does ngAfterViewChecked fire?