Angular Technical Interview Topics
Core Angular concepts for technical interviews. Compact read-and-recall short form info.
Architecture & Modules
What it is: Angular is a full opinionated MVC framework by Google. Applications are organized into NgModules that group related components, services, pipes, and directives.
- Every app has a root
AppModulebootstrapped at startup; feature modules load eagerly or lazily @NgModule({ declarations, imports, providers, exports, bootstrap })defines the module boundarydeclarations: components/directives/pipes owned by this moduleimports: other modules whose exports are needed hereexports: what this module exposes to other modules- Angular 14+ standalone components skip NgModule; dependencies declared directly in
@Component({ imports: [] })
Note:
providedIn: 'root'on services is preferred over listing them inNgModule.providersbecause unused services are tree-shaken out of the production bundle.
Data Binding
What it is: The mechanism that syncs data between the component class and its template.
| Type | Syntax | Direction |
|---|---|---|
| Interpolation | {{ value }} |
Class → Template |
| Property binding | [property]="expr" |
Class → Template |
| Event binding | (event)="handler()" |
Template → Class |
| Two-way binding | [(ngModel)]="prop" |
Both |
- Two-way binding is syntactic sugar:
[(x)]expands to[x]="val" (xChange)="val=$event" [(ngModel)]requiresFormsModule
Note:
[innerHTML]="html"sanitizes by default. To bypass, useDomSanitizer.bypassSecurityTrustHtml(), but avoid unless absolutely necessary.
Components vs Directives
What it is: Both are Angular classes with decorators, but with different purposes.
- Component: a directive with a template. Always has
@Component({ selector, templateUrl, styleUrls }). Owns a view. - Attribute directive: modifies appearance/behavior of an existing element (
ngClass,ngStyle, custom). No template. - Structural directive: changes DOM layout by adding/removing elements (
*ngIf,*ngFor,*ngSwitch). The*prefix desugars to<ng-template>.
Note: A component is a directive, but a directive is not a component. Multiple directives can be applied to one element; only one component can be.
Dependency Injection
What it is: Angular's built-in IoC container. Services are registered in an injector and resolved automatically via constructor injection.
providedIn: 'root'→ app-wide singleton; tree-shakeableprovidedIn: SomeModule→ scoped to that module's injectorproviders: [MyService]in@Component→ new instance per component subtree- Injectors are hierarchical: child injectors walk up to parent until resolved
@Injectable({ providedIn: 'root' })
export class AuthService {
constructor(private http: HttpClient) {}
}
Note: Injecting a service with
providers: [MyService]at the component level breaks the singleton pattern. Useful for intentional instance isolation (e.g., state-per-form).
Lifecycle Hooks
What it is: Interface methods Angular calls at specific points in a component/directive's lifetime.
| Hook | When called |
|---|---|
ngOnChanges |
Input property changes (fires before ngOnInit) |
ngOnInit |
After first ngOnChanges; component fully initialized |
ngDoCheck |
Every change detection run |
ngAfterContentInit |
After <ng-content> projection |
ngAfterViewInit |
After component view + children initialized |
ngOnDestroy |
Before destruction; unsubscribe, cancel timers |
Note:
ngOnChangesonly fires for@Input()property changes. It does not fire for mutations inside an object or array; Angular sees the same reference and skips it.
Services & HttpClient
What it is: Services encapsulate reusable logic. HttpClient is Angular's HTTP layer, returning Observables.
- Import
HttpClientModule(orprovideHttpClient()for standalone) .get<T>(),.post<T>(),.put<T>(),.delete<T>()all returnObservable<T>- Interceptors (
HTTP_INTERCEPTORS) add headers, handle tokens, and log globally
@Injectable({ providedIn: 'root' })
export class UserService {
constructor(private http: HttpClient) {}
getUser(id: number) {
return this.http.get<User>(`/api/users/${id}`).pipe(
catchError(err => throwError(() => err))
);
}
}
Note:
HttpClientreturns cold Observables; no request fires until something subscribes. Unsubscribing cancels the in-flight HTTP request.
Routing & Lazy Loading
What it is: RouterModule maps URL paths to components. Lazy loading defers downloading a feature module until its route is first visited.
<router-outlet>is the placeholder where routed components renderrouterLinkfor declarative navigation;Router.navigate()for imperative- Lazy:
loadChildren: () => import('./feature/feature.module').then(m => m.FeatureModule) - Route guards:
CanActivate,CanDeactivate,CanLoad,Resolve ActivatedRoute.paramsand.queryParamsare Observables
const routes: Routes = [
{
path: 'admin',
canActivate: [AuthGuard],
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
}
];
Note:
CanLoadprevents the module bundle from downloading at all.CanActivateallows the download but blocks rendering. UseCanLoadto hide privileged code from unauthorized users.
Template-driven vs Reactive Forms
What it is: Angular's two approaches to handling user input and validation.
| Template-driven | Reactive | |
|---|---|---|
| Module | FormsModule |
ReactiveFormsModule |
| Model lives | In the template (ngModel) |
In the component class (FormGroup) |
| Validation | HTML attributes | Validator functions |
| Testing | Async, needs DOM | Synchronous |
| Best for | Simple forms | Complex, dynamic forms |
- Reactive building blocks:
FormGroup,FormControl,FormArray - Built-in validators:
Validators.required,Validators.email,Validators.minLength
Note: Reactive forms are synchronous; the model is always available in the component. Template-driven forms rely on directives and are asynchronous, requiring
async/fakeAsyncin tests.
Pipes
What it is: Functions that transform data in templates, applied with the | operator.
- Built-in:
date,currency,percent,uppercase,json,async,slice,keyvalue - Pure pipe: re-runs only when the input reference changes (default). Memoized. Efficient.
- Impure pipe: re-runs on every change detection cycle (
pure: false). Use sparingly. asyncpipe: subscribes to an Observable/Promise, unwraps the value, auto-unsubscribes on destroy
@Pipe({ name: 'truncate' })
export class TruncatePipe implements PipeTransform {
transform(value: string, limit = 50): string {
return value.length > limit ? value.slice(0, limit) + '…' : value;
}
}
Note: The
asyncpipe is the preferred way to consume Observables in templates. It avoids manual subscribe/unsubscribe and prevents memory leaks automatically.
Change Detection
What it is: Angular's mechanism for keeping the view in sync with component state. Runs top-down across the component tree.
- Default strategy: checks the entire tree on every event, timer, or HTTP response (powered by Zone.js)
- OnPush strategy: only checks the component when an
@Input()reference changes, an event fires inside it, or an Observable emits viaasyncpipe ChangeDetectorRef.markForCheck()manually schedules an OnPush component for the next checkdetach()/reattach()give full manual control
Note:
OnPushcombined with immutable data (replace, never mutate) is the primary Angular performance strategy. Always return new object/array references from state updates.
AOT vs JIT Compilation
What it is: Angular compiles HTML templates + TypeScript decorators into JavaScript.
- JIT (Just-in-Time): compilation in the browser at runtime. Larger bundle, slower startup. Used in development (
ng serve). - AOT (Ahead-of-Time): compilation at build time. Smaller bundle, faster startup, catches template errors at build time. Default in production (
ng build). - AOT removes the Angular compiler from the production bundle entirely
Note: AOT catches template binding errors (referencing a non-existent method or property) at build time rather than runtime, a significant advantage in CI/CD pipelines.
NgRx & State Management
What it is: NgRx is a Redux-inspired reactive state library for Angular, built on RxJS Observables.
- Store: single immutable state object
- Actions: describe events (
createAction('[Auth] Login', props<{ user: User }>())) - Reducers: pure functions that produce new state from
(state, action) - Effects: side effects (HTTP calls) triggered by actions, dispatch new actions on completion
- Selectors: memoized projections of store slices
loadUser$ = createEffect(() =>
this.actions$.pipe(
ofType(UserActions.loadUser),
switchMap(({ id }) => this.userService.getUser(id).pipe(
map(user => UserActions.loadUserSuccess({ user })),
catchError(err => of(UserActions.loadUserFailure({ err })))
))
)
);
Note: NgRx adds significant boilerplate. For simpler state, prefer Angular services with
BehaviorSubjectorsignal()-based stores (Angular 16+).
Performance: trackBy & OnPush
What it is: Two practical optimizations to prevent unnecessary DOM recreation and re-rendering.
*ngForwithouttrackBydestroys and recreates all DOM nodes whenever the array reference changestrackByreturns a unique key per item; Angular reuses existing nodes for unchanged items
// template
*ngFor="let item of items; trackBy: trackById"
// component
trackById = (_: number, item: Item) => item.id;
- Pair with
ChangeDetectionStrategy.OnPushon the item component to skip change detection for unchanged items
Note: Combine
trackByon the list withOnPushon the item component. This avoids both DOM churn and change-detection overhead in large lists.
Questions referenced from devinterview.io. Answers written independently.