Recap
Angular — Interview Revision¶
Lifecycle Hooks (in order)¶
constructor— DI only, no inputs yetngOnChanges— fires when@Inputchanges, before initngOnInit— inputs available, do setup herengOnDestroy— clean up subscriptions
constructor vs ngOnInit — constructor for DI only, ngOnInit for logic. Inputs not available in constructor.
Change Detection¶
Default — Zone.js triggers full component tree check on every async event (click, HTTP, setTimeout, Promise).
OnPush — only re-checks component if:
@Inputreference changes (not mutation — new object/array)- Event fires inside component
- Observable emits via
asyncpipe markForCheck()called manually
@Component({
changeDetection: ChangeDetectionStrategy.OnPush
})
Key rule — OnPush compares by reference. Mutating an array doesn't trigger it. Spread to create new reference:
this.items = [...this.items, newItem]; // triggers
this.items.push(newItem); // doesn't trigger
Smart vs Dumb Components¶
Dumb (Presentational):
@Inputfor data in@Outputfor events out- No services, no API calls
- Reusable, easily testable
Smart (Container):
- Injects services
- Makes API calls
- Manages state
- Passes data down, handles events up
Subscriptions — When to Unsubscribe¶
HTTP observables — complete automatically after one response. No unsubscribe needed.
Subjects, timers, WebSockets — never complete. Must unsubscribe.
Four ways:
// 1. Manual
ngOnDestroy() { this.sub.unsubscribe(); }
// 2. takeUntil
private destroy$ = new Subject();
this.data$.pipe(takeUntil(this.destroy$)).subscribe(...);
ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); }
// 3. async pipe — Angular handles it
{{ data$ | async }}
// 4. takeUntilDestroyed (Angular 16+)
this.data$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(...);
RxJS Operators¶
| Scenario | Operator |
|---|---|
| Search input, cancel previous | switchMap |
| Form submit, ignore while busy | exhaustMap |
| Upload queue, one at a time in order | concatMap |
| Independent parallel calls | mergeMap |
setInterval vs setTimeout¶
setTimeout(fn, 3000)— fires once after 3 secondssetInterval(fn, 3000)— fires every 3 seconds regardless
Problem with async inside setInterval: setInterval doesn't await the callback. Calls pile up, responses arrive out of order, stale data overwrites fresh.
Fix — recursive setTimeout:
async function sync() {
await fetch('/api/sync');
setTimeout(sync, 3000); // next only after previous completes
}
Angular fix:
timer(0, 3000).pipe(
switchMap(() => this.http.get('/api/sync')),
takeUntilDestroyed()
).subscribe(...);
DI in Angular¶
- Root —
providedIn: 'root', one instance app-wide - Component —
providers: [MyService]in component, one instance per component - Module —
providersin@NgModule, one instance per module (legacy)
Two-way vs One-way Binding¶
[property]— one-way, parent to child(event)— one-way, child to parent[(ngModel)]— two-way, banana in a box