Angular Interview Questions and Answers
Components, dependency injection, RxJS, signals and Angular tooling.
Whether you are preparing for entry-level Angular interview questions for freshers or senior software engineer interview questions addressing concurrency, scalability, and system architecture, this track provides peer-reviewed model answers with syntax walkthroughs, edge cases, and practical interview tips.
1 How does dependency injection work in Angular? Medium
Dependency injection supplies instances to classes instead of letting them construct collaborators. Providers are registered at the root (providedIn: 'root'), on a route, or in a component's providers array. The injector resolves a token by walking up the hierarchy from the requesting component, so a component-level provider creates a new instance per subtree.
@Injectable({ providedIn: 'root' })
export class UserService { constructor(private http: HttpClient) {} }
export class ProfileComponent { private svc = inject(UserService); }
Tokens can be classes, InjectionTokens or strings. useClass, useValue, useFactory and useExisting control how a token is satisfied, which is how you swap implementations in tests.
Hierarchical injection is what makes tree-shakable services and per-route state possible. providedIn: 'root' lets the bundler drop a service that no one injects, while a component provider scopes lifetime to that component.
2 What is the difference between ViewChild and ContentChild? Medium
Both are query decorators, but they search different places. @ViewChild queries the component's own template, while @ContentChild queries content projected into the component through ng-content.
@Component({ selector: 'app-tabs', template: '<ng-content></ng-content>' })
export class TabsComponent {
@ContentChildren(TabComponent) tabs!: QueryList<TabComponent>;
@ViewChild('panel') panel!: ElementRef;
}
So a tabs component uses ContentChild to find the tabs a consumer projected, and ViewChild to find elements it owns itself. ViewChildren and ContentChildren return a QueryList that updates as the template changes.
Queries accept a local template reference string, a directive or component type, and options { read, static }. static: true resolves the query before ngAfterViewInit or ngAfterContentInit and is required if you need the result in ngOnInit; otherwise results are set later. In newer Angular, the signal-based viewChild() and contentChild() functions are the recommended alternative.
3 How do Observables differ from Promises, and how do you avoid subscription leaks? Medium
A Promise represents a single future value and is eager: it starts when created, cannot be cancelled, and has no operators beyond then and catch. An Observable is lazy, emits zero, one or many values over time, can be cancelled with unsubscribe, and composes through RxJS operators.
this.http.get<User[]>('/api/users').pipe(
map(users => users.filter(u => u.active)),
catchError(() => of([])),
).subscribe(users => this.users = users);
Operators like debounceTime, switchMap, distinctUntilChanged and combineLatest make complex async flows declarative. Angular's HttpClient returns cold observables that fire on subscribe, so forgetting to subscribe means no request.
Subscription leaks are a common bug. Prefer the async pipe, which unsubscribes automatically, or use takeUntilDestroyed, takeUntil with a destroy subject, or firstValueFrom for one-off requests. Never leave a bare long-lived subscribe in a component that never cleans up.
4 When should you use the OnPush change detection strategy? Medium
With the default strategy Angular checks a component on every change-detection run triggered by any event, timer or XHR inside the zone. ChangeDetectionStrategy.OnPush tells Angular to skip the component unless one of its inputs changes by reference, an event originates from the component or its children, an observable bound with the async pipe emits, or you call markForCheck. This dramatically reduces checks in large apps because whole subtrees can be skipped.
@Component({ changeDetection: ChangeDetectionStrategy.OnPush })
Pitfalls: mutating an object in place does not change its reference, so OnPush inputs will not update; create a new array or object instead, or use signals. Async work outside Angular's zone, such as a custom WebSocket callback, will not trigger detection, so call markForCheck or run inside NgZone.run.
OnPush pairs well with immutable data, the async pipe and signals, and it is the default expectation for high-performance Angular components.
5 What is the difference between standalone components and NgModules? Medium
Traditional Angular organises components, directives and pipes into NgModules that declare what belongs together and import other modules. Standalone components skip that: standalone: true, now the default, lets a component import exactly the dependencies it needs directly in its imports array.
@Component({
standalone: true,
imports: [RouterLink, CommonModule],
template: `...`,
})
export class HomeComponent {}
Benefits: less boilerplate, clearer dependency graphs, easier lazy loading because a route can directly loadComponent, better tree-shaking, and a simpler mental model. NgModules still exist for compatibility and for grouping providers or legacy libraries.
The bootstrap API shifted from platformBrowserDynamic().bootstrapModule to bootstrapApplication(AppComponent, { providers: [...] }). Most new Angular projects are fully standalone, and migration is incremental because standalone and module-based declarations interoperate through imports.
6 How do Angular route guards and lazy loading work together? Medium
The router supports guards that run during navigation: CanActivate, CanActivateChild, CanDeactivate for unsaved forms, CanMatch for feature flags, and Resolve to prefetch data. A guard can return a boolean, an Observable, a Promise, or a UrlTree to redirect. Functional guards can use inject().
export const authGuard: CanActivateFn = () => {
const auth = inject(AuthService);
const router = inject(Router);
return auth.isLoggedIn() ? true : router.parseUrl('/login');
};
Lazy loading uses loadChildren for a group of routes or loadComponent for a single standalone component, so the browser downloads that chunk only when the route is visited. Combine it with preloadingStrategy: PreloadAllModules to fetch chunks after the initial render.
Always enforce authorisation on the server as well; client guards improve UX but are not a security boundary. Keep guards small and side-effect free, and return a redirect tree rather than navigating imperatively inside the guard.
Frequently Asked Questions About Angular Interviews
What do hiring managers evaluate in Angular technical rounds?
Technical interviewers look for foundational fluency, idiomatic syntax, clarity when communicating complex logic, and awareness of performance trade-offs (e.g. memory footprint, render performance, and network latency) in production environments.
What are the best interview tips for practicing Angular questions?
Use active recall: summarize each answer in your own words before revealing the model solution. Focus on explaining why a certain approach is chosen rather than just memorizing code syntax.