I've conducted hundreds of Angular interviews over 12 years in fintech. The same mistakes keep appearing. Senior developers with 5+ years of experience trip on the same questions that junior developers struggle with. Not because Angular is hard to use - because Angular is easy to use without understanding how it works.
These five mistakes cost developers job offers. I've seen candidates fail on exactly these points at companies like BNY Mellon, UBS, and major tech firms. Here's how to avoid them.
This is the most common interview failure point. A candidate explains they've used Angular for years, then can't explain why their OnPush component stopped updating.
What is the common change detection mistake?
@Component({ selector: 'app-user-list', template: ` <div *ngFor="let user of users">{{ user.name }}</div> <button (click)="addUser()">Add User</button> `, changeDetection: ChangeDetectionStrategy.OnPush})export class UserListComponent { @Input() users: User[] = []; addUser() { // This WILL NOT update the view! this.users.push({ id: 99, name: 'New User' }); }}
When asked "Why isn't the view updating?", weak answers include:
"Maybe there's a bug?"
"I'd need to see the full code"
"Change detection must be broken"
How should you answer the change detection question?
"OnPush change detection uses reference equality (===) to check if inputs changed. When I call push(), I'm mutating the existing array - the reference stays the same. Angular sees the same object reference and skips the component.
The async pipe subscribes when the component renders and unsubscribes when it's destroyed. It also calls markForCheck() automatically, making it perfect with OnPush.
I prefer the async pipe because it's declarative, works with OnPush, and eliminates the possibility of forgetting to unsubscribe."
When don't you need to unsubscribe?
Knowing what doesn't need cleanup shows deeper understanding:
"Some Observables complete naturally and don't need manual unsubscription:
HTTP requests from HttpClient (they complete after one response)
Router events (handled by Angular internally)
Observables created with of() or from() (they complete immediately)
But infinite streams like interval(), fromEvent(), and store selectors always need cleanup."
Dependency Injection Questions
"How do you ensure a service is a singleton?" This question reveals whether you understand Angular's injector hierarchy.
What is the common dependency injection mistake?
// Candidate says: "I add it to providers"@NgModule({ providers: [UserService] // But which injector?})export class UsersModule { }
Then asked "What if UsersModule is lazy-loaded?" - silence.
How should you answer the singleton service question?
"Angular has a hierarchical injector system. Where you provide a service determines its scope:
1. Root singleton (recommended):
@Injectable({ providedIn: 'root' })export class UserService { }
This creates exactly one instance for the entire application, regardless of where it's injected. It also enables tree-shaking - if the service isn't used, it's removed from the bundle.
2. Module-level provider:
@NgModule({ providers: [UserService]})export class UsersModule { }
If UsersModule is eagerly loaded, UserService goes to the root injector (singleton).
If UsersModule is lazy-loaded, a new child injector is created. The service becomes a singleton within that lazy-loaded module only.
3. Component-level provider:
@Component({ providers: [UserService]})export class UserComponent { }
Every instance of UserComponent gets its own UserService instance. The service is destroyed with the component."
How do you inject non-class values in Angular?
"What if you need to inject a value that isn't a class?" is a common follow-up question.
"I use InjectionToken for non-class values:
export const API_URL = new InjectionToken<string>('apiUrl');// In moduleproviders: [ { provide: API_URL, useValue: 'https://api.example.com' }]// In serviceconstructor(@Inject(API_URL) private apiUrl: string) { }
InjectionToken is type-safe and prevents the magic string problems of the old string-based injection."
Lifecycle Hooks Questions
"What's the difference between the constructor and ngOnInit?" This fundamental question trips up surprisingly many candidates.
What is the common lifecycle hooks mistake?
@Component({ selector: 'app-user', template: `<div>{{ userData?.name }}</div>`})export class UserComponent { @Input() userId!: number; userData: User; constructor(private userService: UserService) { // MISTAKE: Input isn't set yet! this.userService.getUser(this.userId).subscribe( user => this.userData = user ); }}
Weak answer: "ngOnInit is just where Angular wants you to put initialization code."
How should you explain constructor vs ngOnInit?
"The constructor and ngOnInit serve different purposes:
Constructor:
Called by JavaScript, not Angular
@Input properties are NOT set yet
Only use for dependency injection
Keep it simple - no initialization logic
ngOnInit:
Called by Angular after setting @Input properties
First change detection has run
This is where initialization logic belongs
export class UserComponent implements OnInit { @Input() userId!: number; constructor(private userService: UserService) { // userId is undefined here } ngOnInit() { // userId is now available this.loadUser(); }}
The lifecycle order matters:
Constructor
ngOnChanges (first call, inputs are set)
ngOnInit
ngDoCheck
ngAfterContentInit
ngAfterViewInit
... (repeated on changes)
ngOnDestroy"
What should you know about other lifecycle hooks?
"Understanding the full lifecycle becomes critical for complex components:
ngOnChanges: Called before ngOnInit and whenever @Input values change. Receives a SimpleChanges object with previous and current values.
ngAfterViewInit: Safe to access @ViewChild references here, not before. A common mistake is trying to access view children in ngOnInit.
ngAfterContentInit: Safe to access @ContentChild references (projected content).
@Component({...})export class ChartComponent implements AfterViewInit { @ViewChild('canvas') canvas!: ElementRef<HTMLCanvasElement>; ngOnInit() { // this.canvas is undefined! } ngAfterViewInit() { // this.canvas is now available this.initChart(); }}```"
Performance Questions
"How would you optimize an Angular application?" This open-ended question separates those who've dealt with real performance issues from those who haven't.
What is the common performance mistake?
A candidate mentions "use OnPush" but can't explain specific optimizations or why they matter.
How should you answer the optimization question?
"I focus on these key areas:
1. Never call methods in templates:
// BAD - formatDate() runs on every change detectiontemplate: `<div>{{ formatDate(user.createdAt) }}</div>`// GOOD - Pure pipe only recalculates when input changestemplate: `<div>{{ user.createdAt | date:'medium' }}</div>`
Methods execute every change detection cycle. In an app checking 500 components, that's 500 function calls per user interaction.
2. Always use trackBy with ngFor:
<div *ngFor="let item of items; trackBy: trackById"> {{ item.name }}</div>trackById(index: number, item: Item): number { return item.id;}
Without trackBy, Angular destroys and recreates all DOM elements when the array changes. With trackBy, it only updates elements that actually changed.
"Walk me through diagnosing a slow Angular application" is a common follow-up.
"I follow this process:
Profile with Chrome DevTools - Look at the Performance tab for long frames
Check change detection frequency - Add console.log to templates. If it fires constantly, something's triggering unnecessary checks
Use Angular DevTools - The profiler shows exactly which components are checking and how long each takes
Look for common culprits:
Methods or getters in templates
Missing trackBy in ngFor loops
Components not using OnPush
Subscriptions firing too frequently
Bundle analysis - Run ng build --stats-json and use webpack-bundle-analyzer to find oversized dependencies
The fix is usually one of: add OnPush, add trackBy, convert method to pipe, or lazy load a module."
Architecture Questions
After discussing these specifics, interviewers often ask: "If you were building a new Angular application today, what patterns would you establish from day one?"
What patterns would you establish for a new Angular application?
This question reveals your architectural thinking:
"I'd establish these patterns:
OnPush by default - Create a schematic that generates components with OnPush
Async pipe everywhere - Ban manual subscriptions in templates. Use the async pipe and handle loading/error states declaratively
Smart/dumb component pattern - Container components handle data fetching, presentational components only receive @Input and emit @Output
Centralized error handling - HTTP interceptor for API errors, global error handler for unexpected exceptions
Strict TypeScript - Enable strictNullChecks, noImplicitAny, strictPropertyInitialization. Catch bugs at compile time
Lazy loading from the start - Define feature module boundaries early. It's harder to add lazy loading later
These patterns prevent the performance and maintainability issues that make Angular applications hard to work with at scale."
Quick Reference
Topic
Weak Answer
Strong Answer
OnPush not updating
"Change detection is broken"
"Mutation doesn't change reference - use spread operator"
Memory leaks
"I unsubscribe somewhere"
"Async pipe is preferred, or takeUntil pattern"
Service singleton
"Add to providers"
"providedIn: 'root' for tree-shakeable singleton"
Constructor vs ngOnInit
"ngOnInit is Angular's way"
"Constructor: DI only. ngOnInit: inputs are set"
Performance
"Use OnPush"
"TrackBy, pure pipes, lazy loading, avoid template methods"