Land the job you want — prepare
with Real interviews Q&A
Curated interview questions, company-wise guides and coding rounds. Practice mock interviews, improve with feedback, and track your progress.
Angular Interview Questions and Answers
This page contains a comprehensive collection of Angular Interview Questions and Answers designed for freshers, experienced developers, software engineers, and technical interview candidates. The questions range from beginner concepts to advanced Angular topics with practical explanations and real-world examples.
Angular is one of the most popular front-end frameworks used to build enterprise-grade web applications. Modern organizations frequently ask Angular interview questions to evaluate a candidate's understanding of components, modules, dependency injection, routing, RxJS, forms, services, state management, and application architecture.
Whether you are preparing for campus placements, software developer interviews, full-stack developer roles, or senior Angular developer positions, these interview questions will help you strengthen your concepts and improve your confidence before technical interviews.
Why Learn Angular?
Angular is a powerful TypeScript-based framework developed by Google for building scalable single-page applications (SPAs). It offers a complete ecosystem with dependency injection, routing, reactive programming, forms, HTTP communication, testing support, and modern development tools.
Angular developers are in high demand across enterprise software, banking, healthcare, e-commerce, SaaS platforms, ERP systems, and government projects. Mastering Angular interview questions can significantly improve your chances of securing front-end or full-stack development roles.
Topics Covered
- Angular Architecture
- Components & Templates
- Modules
- Data Binding
- Directives
- Pipes
- Dependency Injection
- Services
- Routing
- Reactive Forms
- Template Forms
- RxJS
- Observables
- HTTP Client
- State Management
- Performance Optimization
Angular is a TypeScript-based front-end framework maintained by Google, used to build single-page applications (SPAs) and large-scale web apps.
Unlike React (a library), Angular is a complete framework — it ships with routing, forms, HTTP client, dependency injection, and testing tools built in.
- Components: Reusable UI building blocks
- Templates: HTML with Angular syntax
- Services: Reusable business logic
- Dependency Injection: Built-in DI system
- RxJS: Reactive programming with Observables
A component controls a section of the screen (a view). It consists of a TypeScript class, an HTML template, and optional CSS styles.
import { Component } from '@angular/core';
@Component({
selector: 'app-welcome',
standalone: true,
template: `<h1>Welcome to Angular</h1>`
})
export class WelcomeComponent {}selectordefines the custom HTML tag.template(ortemplateUrl) defines the view.styleUrls/stylesscopes CSS to the component.
An NgModule groups related components, directives, pipes, and services together, and declares what a part of the application needs to work.
Modern Angular (v14+) encourages standalone components which reduce the need for NgModules.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
bootstrap: [AppComponent]
})
export class AppModule {}A template is HTML combined with Angular-specific syntax (bindings, directives, pipes) that tells Angular how to render a component's view.
@Component({
selector: 'app-greeting',
standalone: true,
template: `
<h1>Hello {{ name }}</h1>
<p *ngIf="loggedIn">You are logged in</p>
`
})
export class GreetingComponent {
name = 'Akash';
loggedIn = true;
}Data binding synchronizes data between the component class (TypeScript) and the template (HTML). Angular supports four types of binding.
- Interpolation:
{{ value }}— one-way, component → view - Property binding:
[property]="value"— one-way, component → view - Event binding:
(event)="handler()"— one-way, view → component - Two-way binding:
[(ngModel)]="value"— both directions
Interpolation uses double curly braces {{ }} to embed component data directly into the template as text.
@Component({
selector: 'app-user',
standalone: true,
template: `<h1>Hello, {{ userName }}!</h1>`
})
export class UserComponent {
userName = 'Akash';
}Property binding sets an element's DOM property from a component value using square brackets [ ].
@Component({
selector: 'app-image',
standalone: true,
template: `<img [src]="imageUrl" [alt]="imageAlt">
<button [disabled]="isDisabled">Submit</button>`
})
export class ImageComponent {
imageUrl = 'logo.png';
imageAlt = 'Company Logo';
isDisabled = true;
}Event binding listens for DOM events (click, input, submit) using parentheses ( ) and calls a component method in response.
@Component({
selector: 'app-button',
standalone: true,
template: `<button (click)="handleClick()">Click Me</button>`
})
export class ButtonComponent {
handleClick() {
alert('Button Clicked');
}
}Two-way binding combines property and event binding using the banana-in-a-box syntax [( )], keeping the template and component in sync in both directions.
Requires importing FormsModule.
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-input',
standalone: true,
imports: [FormsModule],
template: `
<input [(ngModel)]="name" placeholder="Enter name">
<p>Hello, {{ name }}</p>
`
})
export class InputComponent {
name = '';
}Directives are classes that add behavior to elements in the DOM. Angular has three kinds.
- Component directives: Directives with a template (every component is a directive).
- Structural directives: Change DOM layout —
*ngIf,*ngFor,*ngSwitch. - Attribute directives: Change appearance/behavior —
ngClass,ngStyle, custom directives.
*ngIf is a structural directive that conditionally adds or removes an element from the DOM based on a boolean expression.
@Component({
selector: 'app-status',
standalone: true,
imports: [CommonModule],
template: `
<h1 *ngIf="isLoggedIn; else loggedOut">Welcome back!</h1>
<ng-template #loggedOut>
<h1>Please Login</h1>
</ng-template>
`
})
export class StatusComponent {
isLoggedIn = true;
}*ngFor is a structural directive used to render a list of items by repeating a template for each item in an array.
@Component({
selector: 'app-users',
standalone: true,
imports: [CommonModule],
template: `
<ul>
<li *ngFor="let user of users; let i = index">
{{ i + 1 }}. {{ user }}
</li>
</ul>
`
})
export class UsersComponent {
users = ['Akash', 'Rahul', 'Aman'];
}ngClass conditionally applies one or more CSS classes to an element based on component data.
@Component({
selector: 'app-badge',
standalone: true,
imports: [CommonModule],
template: `
<div [ngClass]="{ active: isActive, error: hasError }">
Status
</div>
`
})
export class BadgeComponent {
isActive = true;
hasError = false;
}ngStyle dynamically sets inline CSS styles on an element based on component data.
@Component({
selector: 'app-box',
standalone: true,
imports: [CommonModule],
template: `
<div [ngStyle]="{ 'color': textColor, 'font-size.px': fontSize }">
Styled Text
</div>
`
})
export class BoxComponent {
textColor = 'blue';
fontSize = 20;
}Pipes transform displayed values in a template, such as formatting dates, currency, or text case, using the | symbol.
@Component({
selector: 'app-profile',
standalone: true,
imports: [CommonModule],
template: `
<p>{{ name | uppercase }}</p>
<p>{{ price | currency:'INR' }}</p>
<p>{{ today | date:'longDate' }}</p>
`
})
export class ProfileComponent {
name = 'akash';
price = 499;
today = new Date();
}- Built-in pipes:
uppercase,lowercase,date,currency,percent,json,async. - Pipes can be chained:
{{ value | pipe1 | pipe2 }}.
A service is a class that holds reusable business logic (API calls, shared state, utility functions) that can be injected into any component.
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class UserService {
getUsers() {
return ['Akash', 'Rahul', 'Aman'];
}
}
// Using the service in a component
@Component({ selector: 'app-list', standalone: true, template: `...` })
export class ListComponent {
constructor(private userService: UserService) {}
users = this.userService.getUsers();
}Dependency Injection is a design pattern where a class receives its dependencies (like services) from an external source rather than creating them itself. Angular has a built-in DI system.
@Injectable({ providedIn: 'root' })
export class LoggerService {
log(msg: string) { console.log(msg); }
}
@Component({ selector: 'app-root', standalone: true, template: `...` })
export class AppComponent {
// Angular injects LoggerService automatically
constructor(private logger: LoggerService) {
this.logger.log('App started');
}
}- Improves testability — services can be mocked easily.
- Promotes loose coupling between classes.
providedIn: 'root'makes a service a singleton across the app.
The Angular CLI is a command-line tool for creating, building, testing, and generating Angular projects and code artifacts.
# Install
npm install -g @angular/cli
# Create a new project
ng new my-app
# Generate a component
ng generate component user-profile
# Serve the app locally
ng serve
# Build for production
ng build --configuration productionDecorators are functions prefixed with @ that attach metadata to classes, properties, or methods, telling Angular how to treat them.
@Component()— marks a class as a component.@NgModule()— marks a class as a module.@Injectable()— marks a class as a service.@Input()/@Output()— mark properties for data flow.@Directive()— marks a class as a directive.
@Component is a decorator that defines a class as an Angular component, specifying its selector, template, styles, and other metadata.
@Component({
selector: 'app-card',
standalone: true,
templateUrl: './card.component.html',
styleUrls: ['./card.component.css']
})
export class CardComponent {
title = 'My Card';
}@Input() lets a parent component pass data down into a child component, similar to props in React.
@Component({
selector: 'app-child',
standalone: true,
template: `<h1>Hello {{ name }}</h1>`
})
export class ChildComponent {
@Input() name!: string;
}
// Parent template
// <app-child [name]="'Akash'"></app-child>@Output() combined with EventEmitter lets a child component send data or events back up to its parent.
@Component({
selector: 'app-child',
standalone: true,
template: `<button (click)="notify()">Notify Parent</button>`
})
export class ChildComponent {
@Output() clicked = new EventEmitter<string>();
notify() {
this.clicked.emit('Child says hello');
}
}
// Parent template
// <app-child (clicked)="onChildClick($event)"></app-child>Angular components communicate using @Input() (parent → child) and @Output() with EventEmitter (child → parent).
// parent.component.ts
@Component({
selector: 'app-parent',
standalone: true,
imports: [ChildComponent],
template: `
<app-child [message]="parentMsg" (reply)="handleReply($event)"></app-child>
<p>Child replied: {{ childReply }}</p>
`
})
export class ParentComponent {
parentMsg = 'Hello from parent';
childReply = '';
handleReply(msg: string) { this.childReply = msg; }
}A template reference variable, declared with #, gives you direct access to a DOM element or directive instance within the template.
@Component({
selector: 'app-focus',
standalone: true,
template: `
<input #box type="text">
<button (click)="box.focus()">Focus Input</button>
`
})
export class FocusComponent {}<ng-content> enables content projection — it lets a parent component insert custom HTML into a child component's template, similar to props.children in React.
// card.component.ts
@Component({
selector: 'app-card',
standalone: true,
template: `
<div class="card">
<ng-content></ng-content>
</div>
`
})
export class CardComponent {}
// Usage:
// <app-card><h2>Projected Title</h2></app-card><ng-container> is a logical grouping element that doesn't render any actual DOM node. It's used to apply structural directives without adding an extra wrapper element.
<ng-container *ngIf="showContent">
<h1>Title</h1>
<p>Description</p>
</ng-container><ng-template> defines a chunk of HTML that Angular does not render immediately — it's rendered later, e.g. via *ngIf/else or by a structural directive.
<div *ngIf="isLoading; else content">Loading...</div>
<ng-template #content>
<p>Data loaded successfully!</p>
</ng-template>Standalone components (Angular 14+) don't need to be declared inside an NgModule. They import their own dependencies directly, simplifying the mental model.
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-search',
standalone: true,
imports: [CommonModule, FormsModule],
template: `<input [(ngModel)]="query">`
})
export class SearchComponent {
query = '';
}- No NgModule required.
- Bootstrapped directly with
bootstrapApplication(). - The recommended default approach in modern Angular.
AngularJS (v1.x) is the original JavaScript framework built on the $scope and MVC pattern. Angular (v2+) is a complete rewrite in TypeScript with a component-based architecture.
- AngularJS uses JavaScript; Angular uses TypeScript.
- AngularJS is controller/scope-based; Angular is component-based.
- Angular has better performance, mobile support, and CLI tooling.
- AngularJS reached end-of-life; Angular receives regular major releases.
Every Angular component goes through a series of lifecycle hooks from creation to destruction, letting you run code at specific moments.
ngOnChanges— when an @Input() value changes.ngOnInit— once, after the first ngOnChanges.ngAfterViewInit— after the component's view is initialized.ngOnDestroy— just before the component is destroyed.
ngOnInit() is a lifecycle hook that runs once, right after Angular initializes the component's inputs. It's the recommended place for initialization logic like fetching data.
import { Component, OnInit } from '@angular/core';
@Component({ selector: 'app-user', standalone: true, template: `{{ user }}` })
export class UserComponent implements OnInit {
user = '';
ngOnInit() {
this.user = 'Loaded from ngOnInit';
}
}ngOnChanges() runs whenever a bound @Input() property changes. It receives a SimpleChanges object describing the previous and current values.
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
@Component({ selector: 'app-child', standalone: true, template: `{{ count }}` })
export class ChildComponent implements OnChanges {
@Input() count = 0;
ngOnChanges(changes: SimpleChanges) {
console.log('Previous:', changes['count'].previousValue);
console.log('Current:', changes['count'].currentValue);
}
}ngOnDestroy() runs just before Angular destroys a component. It's used to clean up subscriptions, timers, and event listeners to avoid memory leaks.
import { Component, OnDestroy } from '@angular/core';
import { Subscription, interval } from 'rxjs';
@Component({ selector: 'app-timer', standalone: true, template: `{{ tick }}` })
export class TimerComponent implements OnDestroy {
tick = 0;
private sub: Subscription = interval(1000).subscribe(() => this.tick++);
ngOnDestroy() {
this.sub.unsubscribe();
}
}ngAfterViewInit() runs once, after Angular has fully initialized the component's view and child views. It's the right place to access @ViewChild elements.
import { Component, AfterViewInit, ViewChild, ElementRef } from '@angular/core';
@Component({ selector: 'app-box', standalone: true, template: `<div #box>Box</div>` })
export class BoxComponent implements AfterViewInit {
@ViewChild('box') boxRef!: ElementRef;
ngAfterViewInit() {
console.log(this.boxRef.nativeElement.textContent);
}
}@ViewChild() gives a component direct access to a child element, directive, or component instance from its own template.
import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
@Component({
selector: 'app-focus',
standalone: true,
template: `<input #inputBox type="text">
<button (click)="focusInput()">Focus</button>`
})
export class FocusComponent implements AfterViewInit {
@ViewChild('inputBox') inputBox!: ElementRef;
ngAfterViewInit() {}
focusInput() {
this.inputBox.nativeElement.focus();
}
}@ContentChild() accesses an element that was projected into a component via <ng-content>, rather than defined in its own template.
@Component({
selector: 'app-panel',
standalone: true,
template: `<ng-content></ng-content>`
})
export class PanelComponent implements AfterContentInit {
@ContentChild('projected') projectedEl!: ElementRef;
ngAfterContentInit() {
console.log(this.projectedEl.nativeElement.textContent);
}
}
// Usage: <app-panel><p #projected>Hello</p></app-panel>The Angular Router enables navigation between views/components based on the URL, without full page reloads — powering single-page application navigation.
import { Routes } from '@angular/router';
export const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'about', component: AboutComponent },
{ path: 'users/:id', component: UserDetailComponent },
];
// main.ts
bootstrapApplication(AppComponent, {
providers: [provideRouter(routes)]
});Route parameters let you pass dynamic values through the URL, such as an item ID, and read them inside the target component.
// Route definition
{ path: 'users/:id', component: UserDetailComponent }
// user-detail.component.ts
import { ActivatedRoute } from '@angular/router';
export class UserDetailComponent implements OnInit {
constructor(private route: ActivatedRoute) {}
ngOnInit() {
const id = this.route.snapshot.paramMap.get('id');
console.log('User ID:', id);
}
}Route guards control access to routes — for example, blocking navigation unless a user is authenticated. CanActivate is the most common guard type.
import { CanActivateFn } from '@angular/router';
import { inject } from '@angular/core';
export const authGuard: CanActivateFn = () => {
const auth = inject(AuthService);
return auth.isLoggedIn() ? true : false;
};
// Route definition
{ path: 'dashboard', component: DashboardComponent, canActivate: [authGuard] }Lazy loading loads a feature module or standalone component only when its route is visited, reducing the initial bundle size.
export const routes: Routes = [
{
path: 'admin',
loadComponent: () =>
import('./admin/admin.component').then(m => m.AdminComponent)
}
];Reactive forms build form controls explicitly in the component class using FormGroup and FormControl, giving full programmatic control and easy validation.
import { FormGroup, FormControl, ReactiveFormsModule } from '@angular/forms';
@Component({
selector: 'app-login',
standalone: true,
imports: [ReactiveFormsModule],
template: `
<form [formGroup]="loginForm" (ngSubmit)="onSubmit()">
<input formControlName="email">
<input formControlName="password" type="password">
<button type="submit">Login</button>
</form>
`
})
export class LoginComponent {
loginForm = new FormGroup({
email: new FormControl(''),
password: new FormControl(''),
});
onSubmit() {
console.log(this.loginForm.value);
}
}Template-driven forms rely on directives like ngModel directly in the HTML template, with Angular building the form model behind the scenes. Simpler, but less scalable for complex forms.
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-signup',
standalone: true,
imports: [FormsModule],
template: `
<form #signupForm="ngForm" (ngSubmit)="onSubmit(signupForm.value)">
<input name="email" ngModel required>
<button type="submit">Sign Up</button>
</form>
`
})
export class SignupComponent {
onSubmit(value: any) {
console.log(value);
}
}Angular provides built-in validators (required, minLength, email, etc.) for both reactive and template-driven forms, plus support for custom validators.
import { FormGroup, FormControl, Validators } from '@angular/forms';
export class RegisterComponent {
form = new FormGroup({
email: new FormControl('', [Validators.required, Validators.email]),
password: new FormControl('', [Validators.required, Validators.minLength(6)]),
});
get emailInvalid() {
return this.form.get('email')!.invalid && this.form.get('email')!.touched;
}
}FormBuilder is a service that provides shorthand syntax for creating FormGroup and FormControl instances, reducing boilerplate.
import { FormBuilder, Validators } from '@angular/forms';
export class ProfileComponent {
constructor(private fb: FormBuilder) {}
form = this.fb.group({
name: ['', Validators.required],
age: [18, Validators.min(0)],
});
}HttpClient is Angular's built-in service for making HTTP requests (GET, POST, PUT, DELETE) and returns Observables.
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class UserService {
constructor(private http: HttpClient) {}
getUsers() {
return this.http.get('https://jsonplaceholder.typicode.com/users');
}
}An Observable represents a stream of values delivered over time. Angular uses Observables (via RxJS) heavily for HTTP requests, forms, and events.
import { Observable } from 'rxjs';
const numbers$ = new Observable<number>(subscriber => {
subscriber.next(1);
subscriber.next(2);
subscriber.complete();
});
numbers$.subscribe(value => console.log(value));- Observables are lazy — code only runs when subscribed.
- Can emit multiple values over time, unlike a Promise.
- Support cancellation via
unsubscribe().
RxJS (Reactive Extensions for JavaScript) is a library for composing asynchronous, event-based code using Observables and operators. Angular is built on top of it.
import { of } from 'rxjs';
import { map, filter } from 'rxjs/operators';
of(1, 2, 3, 4, 5).pipe(
filter(n => n % 2 === 0),
map(n => n * 10)
).subscribe(val => console.log(val)); // 20, 40RxJS operators transform, filter, or inspect values emitted by an Observable, and are combined using .pipe().
this.http.get<User[]>('/api/users').pipe(
tap(users => console.log('Fetched', users.length)),
map(users => users.filter(u => u.active))
).subscribe(activeUsers => {
this.users = activeUsers;
});map— transforms each emitted value.filter— only passes values matching a condition.tap— runs a side effect without changing the value.
A Subscription is returned when you call .subscribe() on an Observable. Failing to unsubscribe from long-lived Observables can cause memory leaks.
export class UserListComponent implements OnDestroy {
private sub!: Subscription;
ngOnInit() {
this.sub = this.userService.getUsers().subscribe(users => {
this.users = users;
});
}
ngOnDestroy() {
this.sub.unsubscribe();
}
}The async pipe subscribes to an Observable (or Promise) directly in the template and automatically unsubscribes when the component is destroyed — no manual subscription management needed.
@Component({
selector: 'app-users',
standalone: true,
imports: [CommonModule],
template: `
<ul>
<li *ngFor="let user of users$ | async">{{ user.name }}</li>
</ul>
`
})
export class UsersComponent {
users$ = this.userService.getUsers();
constructor(private userService: UserService) {}
}A custom pipe lets you define your own value transformation for use in templates, implemented via the @Pipe decorator and a transform() method.
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({ name: 'truncate', standalone: true })
export class TruncatePipe implements PipeTransform {
transform(value: string, limit = 20): string {
return value.length > limit ? value.slice(0, limit) + '...' : value;
}
}
// Usage: {{ description | truncate:50 }}A custom attribute directive changes the appearance or behavior of an element. It's created using the @Directive decorator.
import { Directive, ElementRef, HostListener } from '@angular/core';
@Directive({ selector: '[appHighlight]', standalone: true })
export class HighlightDirective {
constructor(private el: ElementRef) {}
@HostListener('mouseenter') onEnter() {
this.el.nativeElement.style.backgroundColor = 'yellow';
}
@HostListener('mouseleave') onLeave() {
this.el.nativeElement.style.backgroundColor = '';
}
}
// Usage: <p appHighlight>Hover over me</p>A structural directive changes the DOM layout by adding or removing elements, using TemplateRef and ViewContainerRef.
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
@Directive({ selector: '[appUnless]', standalone: true })
export class UnlessDirective {
constructor(private tpl: TemplateRef<any>, private vcr: ViewContainerRef) {}
@Input() set appUnless(condition: boolean) {
if (!condition) {
this.vcr.createEmbeddedView(this.tpl);
} else {
this.vcr.clear();
}
}
}
// Usage: <p *appUnless="isHidden">Shown when isHidden is false</p>providedIn: 'root' registers a service with Angular's root injector, making it a singleton shared across the whole application, and enabling tree-shaking if it's never used.
@Injectable({ providedIn: 'root' })
export class CartService {
private items: string[] = [];
add(item: string) { this.items.push(item); }
}@Injectable() marks a class as available to Angular's dependency injection system, allowing it to be injected into components, directives, or other services.
@Injectable({ providedIn: 'root' })
export class AuthService {
private loggedIn = false;
login() { this.loggedIn = true; }
isLoggedIn() { return this.loggedIn; }
}Change detection is the mechanism Angular uses to keep the view in sync with the component's data. By default, Angular checks every component in the tree whenever an event, timer, or HTTP response occurs (via Zone.js).
ChangeDetectionStrategy.OnPush tells Angular to skip checking a component unless its @Input() reference changes, an event fires inside it, or an Observable it's tracking emits — significantly improving performance.
import { Component, ChangeDetectionStrategy, Input } from '@angular/core';
@Component({
selector: 'app-item',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
template: `{{ item.name }}`
})
export class ItemComponent {
@Input() item!: { name: string };
}trackBy gives Angular a way to identify which items in a list changed, avoiding unnecessary re-renders of unchanged DOM elements.
@Component({
selector: 'app-list',
standalone: true,
imports: [CommonModule],
template: `
<li *ngFor="let user of users; trackBy: trackByUserId">
{{ user.name }}
</li>
`
})
export class ListComponent {
users = [{ id: 1, name: 'Akash' }, { id: 2, name: 'Rahul' }];
trackByUserId(index: number, user: any) {
return user.id;
}
}Angular's animation system, built on the Web Animations API, lets you define transitions and states declaratively using @angular/animations.
import { trigger, state, style, transition, animate } from '@angular/animations';
@Component({
selector: 'app-toggle',
standalone: true,
template: `<div [@fade]="state">Content</div>`,
animations: [
trigger('fade', [
state('void', style({ opacity: 0 })),
transition(':enter', [animate('300ms ease-in')]),
])
]
})
export class ToggleComponent {
state = 'visible';
}Dynamic component loading creates and inserts a component at runtime rather than declaring it directly in a template — useful for modals, plugins, or widget systems.
import { Component, ViewContainerRef } from '@angular/core';
@Component({ selector: 'app-host', standalone: true, template: `<ng-container #container></ng-container>` })
export class HostComponent {
constructor(private vcr: ViewContainerRef) {}
loadWidget() {
this.vcr.createComponent(WidgetComponent);
}
}Zone.js is a library Angular uses to detect when asynchronous operations (clicks, timers, HTTP responses) complete, so it knows when to run change detection. Newer Angular versions support zoneless change detection with Signals.
NgRx is a Redux-inspired state management library for Angular, built on RxJS. It centralizes application state in a single store using actions, reducers, and selectors.
// Action
export const increment = createAction('[Counter] Increment');
// Reducer
export const counterReducer = createReducer(
0,
on(increment, state => state + 1)
);
// Component
export class CounterComponent {
count$ = this.store.select(state => state.count);
constructor(private store: Store<{ count: number }>) {}
increment() { this.store.dispatch(increment()); }
}These flattening operators manage inner Observables triggered by an outer Observable, each with different cancellation/ordering behavior.
searchInput$.pipe(
debounceTime(300),
switchMap(query => this.http.get(`/api/search?q=${query}`))
).subscribe(results => this.results = results);switchMap— cancels the previous inner Observable (great for search-as-you-type).mergeMap— runs all inner Observables concurrently.concatMap— runs inner Observables sequentially, one after another.exhaustMap— ignores new emissions while one is in progress (great for preventing double form submits).
An HTTP interceptor intercepts outgoing requests and incoming responses globally, useful for attaching auth tokens, logging, or handling errors in one place.
import { HttpInterceptorFn } from '@angular/common/http';
export const authInterceptor: HttpInterceptorFn = (req, next) => {
const authReq = req.clone({
setHeaders: { Authorization: `Bearer TOKEN` }
});
return next(authReq);
};
// main.ts
bootstrapApplication(AppComponent, {
providers: [provideHttpClient(withInterceptors([authInterceptor]))]
});A resolver pre-fetches data before a route activates, ensuring the component has the data ready as soon as it renders.
import { ResolveFn } from '@angular/router';
export const userResolver: ResolveFn<User> = (route) => {
const userService = inject(UserService);
return userService.getUser(route.paramMap.get('id')!);
};
// Route definition
{ path: 'users/:id', component: UserDetailComponent, resolve: { user: userResolver } }Async validators perform validation that requires an asynchronous operation, such as checking username availability against a server.
export function uniqueUsernameValidator(userService: UserService): AsyncValidatorFn {
return (control: AbstractControl) => {
return userService.checkUsername(control.value).pipe(
map(taken => (taken ? { usernameTaken: true } : null))
);
};
}
// Usage
new FormControl('', [], [uniqueUsernameValidator(this.userService)]);Renderer2 is a service that abstracts DOM manipulation, allowing directives and components to safely modify elements in a platform-independent way (works with server-side rendering and Web Workers).
import { Directive, ElementRef, Renderer2, OnInit } from '@angular/core';
@Directive({ selector: '[appBorder]', standalone: true })
export class BorderDirective implements OnInit {
constructor(private el: ElementRef, private renderer: Renderer2) {}
ngOnInit() {
this.renderer.setStyle(this.el.nativeElement, 'border', '2px solid red');
}
}ElementRef wraps a reference to a native DOM element, giving direct access to it. It's often used with Renderer2 to avoid unsafe direct DOM manipulation.
import { Component, ElementRef, ViewChild } from '@angular/core';
@Component({ selector: 'app-box', standalone: true, template: `<div #box>Box</div>` })
export class BoxComponent {
@ViewChild('box') box!: ElementRef;
logWidth() {
console.log(this.box.nativeElement.offsetWidth);
}
}Angular Universal renders Angular applications on the server, producing static HTML that's sent to the browser before the client-side app takes over (hydration). This improves first paint time and SEO.
ng add @angular/ssr
npm run build
npm run serve:ssrSignals (Angular 16+) are a reactive primitive that hold a value and notify consumers when it changes, offering fine-grained reactivity as an alternative to Zone.js-based change detection.
import { signal } from '@angular/core';
@Component({
selector: 'app-counter',
standalone: true,
template: `
<h1>{{ count() }}</h1>
<button (click)="increment()">+</button>
`
})
export class CounterComponent {
count = signal(0);
increment() { this.count.update(c => c + 1); }
}computed() creates a read-only signal derived from other signals. It automatically recalculates only when its dependencies change.
import { signal, computed } from '@angular/core';
export class CartComponent {
price = signal(100);
quantity = signal(2);
total = computed(() => this.price() * this.quantity());
}effect() runs a side effect (like logging or syncing to localStorage) automatically whenever a signal it reads changes.
import { signal, effect } from '@angular/core';
export class ThemeComponent {
theme = signal('light');
constructor() {
effect(() => {
console.log('Theme changed to:', this.theme());
localStorage.setItem('theme', this.theme());
});
}
}bootstrapApplication() launches an Angular app directly from a standalone root component, without needing an AppModule.
import { bootstrapApplication } from '@angular/platform-browser';
import { provideRouter } from '@angular/router';
import { AppComponent } from './app/app.component';
import { routes } from './app/app.routes';
bootstrapApplication(AppComponent, {
providers: [provideRouter(routes)]
});Module Federation allows multiple independently-built and deployed Angular applications (micro frontends) to share code and be composed together at runtime, often via @angular-architects/module-federation.
TestBed is Angular's testing utility for configuring and creating component test environments. Tests typically run with Jasmine as the framework and Karma as the test runner.
import { TestBed } from '@angular/core/testing';
import { CounterComponent } from './counter.component';
describe('CounterComponent', () => {
it('should increment count', () => {
const fixture = TestBed.createComponent(CounterComponent);
const component = fixture.componentInstance;
component.increment();
expect(component.count()).toBe(1);
});
});The Angular CDK's Virtual Scroll renders only the DOM elements currently visible in a viewport, dramatically improving performance for very long lists.
import { ScrollingModule } from '@angular/cdk/scrolling';
@Component({
selector: 'app-big-list',
standalone: true,
imports: [ScrollingModule],
template: `
<cdk-virtual-scroll-viewport itemSize="50" style="height: 400px">
<div *cdkVirtualFor="let item of items">{{ item }}</div>
</cdk-virtual-scroll-viewport>
`
})
export class BigListComponent {
items = Array.from({ length: 10000 }, (_, i) => `Item #${i}`);
}Angular's built-in internationalization (i18n) system marks text for translation using the i18n attribute, then generates locale-specific builds.
<h1 i18n="@@welcomeMessage">Welcome to our site</h1>
# Extract translatable strings
ng extract-i18nAngular Material is Google's official UI component library implementing Material Design — buttons, dialogs, tables, form fields, and more, ready to use with Angular.
import { MatButtonModule } from '@angular/material/button';
@Component({
selector: 'app-action',
standalone: true,
imports: [MatButtonModule],
template: `<button mat-raised-button color="primary">Save</button>`
})
export class ActionComponent {}InjectionToken creates a unique DI token for values that aren't classes (like config objects or primitives), which can't be used as normal injection tokens.
import { InjectionToken } from '@angular/core';
export const API_URL = new InjectionToken<string>('API_URL');
// Providing it
{ provide: API_URL, useValue: 'https://api.example.com' }
// Injecting it
constructor(@Inject(API_URL) private apiUrl: string) {}Setting multi: true on a provider lets multiple values be registered under the same DI token, collected into an array — commonly used for interceptors or validators.
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true },
]Multiple <ng-content select="..."> slots let a component project different pieces of content into different locations based on a CSS selector.
@Component({
selector: 'app-layout',
standalone: true,
template: `
<header><ng-content select="[header]"></ng-content></header>
<main><ng-content></ng-content></main>
`
})
export class LayoutComponent {}
// Usage:
// <app-layout>
// <h1 header>Title</h1>
// <p>Main content</p>
// </app-layout>The constructor is a plain TypeScript/JavaScript feature used for dependency injection and basic class setup. ngOnInit is an Angular lifecycle hook that runs after Angular has set the component's inputs — the right place for initialization logic that depends on those inputs.
A pure pipe (the default) only re-runs when its input reference changes. An impure pipe (pure: false) re-runs on every change-detection cycle, which is more flexible but can hurt performance.
@Pipe({ name: 'filterActive', standalone: true, pure: false })
export class FilterActivePipe implements PipeTransform {
transform(items: any[]): any[] {
return items.filter(item => item.active);
}
}All three are special Observables that can also emit values manually (multicasting), but they differ in what they give new subscribers.
const subject = new BehaviorSubject<number>(0);
subject.subscribe(val => console.log('A:', val)); // A: 0
subject.next(1);
subject.subscribe(val => console.log('B:', val)); // B: 1 (gets latest immediately)- Subject: No initial value; new subscribers only get future emissions.
- BehaviorSubject: Requires an initial value; new subscribers immediately get the most recent value.
- ReplaySubject: Replays a specified number of past emissions to new subscribers.
Schematics are code generators used by the Angular CLI (ng generate) to scaffold components, services, modules, and even apply custom automated code transformations across a codebase.
ng generate component user-card
ng generate service auth
ng generate guard admin-only
# Custom schematics can be built with @angular-devkit/schematicsA simple counter component using component class state and event binding.
import { Component } from '@angular/core';
@Component({
selector: 'app-counter',
standalone: true,
template: `
<h1>Count: {{ count }}</h1>
<button (click)="count = count + 1">Increase</button>
<button (click)="count = count - 1">Decrease</button>
<button (click)="count = 0">Reset</button>
`
})
export class CounterComponent {
count = 0;
}Rendering a list efficiently using trackBy to avoid unnecessary DOM re-creation.
@Component({
selector: 'app-user-list',
standalone: true,
imports: [CommonModule],
template: `
<li *ngFor="let user of users; trackBy: trackById">{{ user.name }}</li>
`
})
export class UserListComponent {
users = [{ id: 1, name: 'Akash' }, { id: 2, name: 'Rahul' }];
trackById(index: number, user: any) { return user.id; }
}A live-updating input field bound to a component property with [(ngModel)].
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-name-input',
standalone: true,
imports: [FormsModule],
template: `
<input [(ngModel)]="name" placeholder="Enter name">
<h1>Hello {{ name }}</h1>
`
})
export class NameInputComponent {
name = '';
}A login form built with FormGroup and validators.
@Component({
selector: 'app-login',
standalone: true,
imports: [ReactiveFormsModule],
template: `
<form [formGroup]="form" (ngSubmit)="submit()">
<input formControlName="email">
<input formControlName="password" type="password">
<button [disabled]="form.invalid" type="submit">Login</button>
</form>
`
})
export class LoginComponent {
form = new FormGroup({
email: new FormControl('', [Validators.required, Validators.email]),
password: new FormControl('', Validators.required),
});
submit() { console.log(this.form.value); }
}Fetching a list of users from an API and rendering it with the async pipe.
@Injectable({ providedIn: 'root' })
export class UserService {
constructor(private http: HttpClient) {}
getUsers() {
return this.http.get<any[]>('https://jsonplaceholder.typicode.com/users');
}
}
@Component({
selector: 'app-users',
standalone: true,
imports: [CommonModule],
template: `<li *ngFor="let u of users$ | async">{{ u.name }}</li>`
})
export class UsersComponent {
users$ = this.userService.getUsers();
constructor(private userService: UserService) {}
}A pipe that reverses a string, used directly in a template.
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({ name: 'reverse', standalone: true })
export class ReversePipe implements PipeTransform {
transform(value: string): string {
return value.split('').reverse().join('');
}
}
// Usage: {{ 'Angular' | reverse }} -> ralugnAAn attribute directive that highlights text on hover.
@Directive({ selector: '[appHighlight]', standalone: true })
export class HighlightDirective {
constructor(private el: ElementRef) {}
@HostListener('mouseenter') onEnter() {
this.el.nativeElement.style.color = 'red';
}
@HostListener('mouseleave') onLeave() {
this.el.nativeElement.style.color = '';
}
}
// Usage: <p appHighlight>Hover me</p>A shared counter service injected into multiple components.
@Injectable({ providedIn: 'root' })
export class CounterService {
count = 0;
increment() { this.count++; }
}
@Component({ selector: 'app-a', standalone: true, template: `{{ counter.count }}` })
export class AComponent {
constructor(public counter: CounterService) {}
}Navigating programmatically using the Router service.
import { Router } from '@angular/router';
@Component({
selector: 'app-nav',
standalone: true,
template: `<button (click)="goToProfile()">Go to Profile</button>`
})
export class NavComponent {
constructor(private router: Router) {}
goToProfile() {
this.router.navigate(['/profile', 42]);
}
}Accessing and focusing an input element directly via @ViewChild.
@Component({
selector: 'app-focus',
standalone: true,
template: `<input #box><button (click)="focusInput()">Focus</button>`
})
export class FocusComponent {
@ViewChild('box') box!: ElementRef;
focusInput() { this.box.nativeElement.focus(); }
}A child button that notifies its parent with a payload when clicked.
@Component({
selector: 'app-child',
standalone: true,
template: `<button (click)="send()">Send</button>`
})
export class ChildComponent {
@Output() message = new EventEmitter<string>();
send() { this.message.emit('Hello from child'); }
}
// Parent template:
// <app-child (message)="onMessage($event)"></app-child>Reading a projected element's text content after content initialization.
@Component({
selector: 'app-panel',
standalone: true,
template: `<ng-content></ng-content>`
})
export class PanelComponent implements AfterContentInit {
@ContentChild('label') label!: ElementRef;
ngAfterContentInit() {
console.log(this.label.nativeElement.textContent);
}
}
// Usage: <app-panel><span #label>Projected</span></app-panel>A functional CanActivate guard that redirects unauthenticated users.
export const authGuard: CanActivateFn = () => {
const auth = inject(AuthService);
const router = inject(Router);
if (auth.isLoggedIn()) return true;
router.navigate(['/login']);
return false;
};An interceptor that logs every outgoing request's URL.
export const loggingInterceptor: HttpInterceptorFn = (req, next) => {
console.log('Request URL:', req.url);
return next(req);
};A basic counter built with Angular Signals instead of plain fields.
@Component({
selector: 'app-signal-counter',
standalone: true,
template: `<h1>{{ count() }}</h1><button (click)="count.set(count() + 1)">+</button>`
})
export class SignalCounterComponent {
count = signal(0);
}Deriving a total price from quantity and price signals.
export class CartComponent {
price = signal(250);
qty = signal(3);
total = computed(() => this.price() * this.qty());
}Syncing a signal's value to localStorage whenever it changes.
export class SettingsComponent {
theme = signal('dark');
constructor() {
effect(() => localStorage.setItem('theme', this.theme()));
}
}Loading a standalone settings component only when its route is visited.
export const routes: Routes = [
{
path: 'settings',
loadComponent: () =>
import('./settings/settings.component').then(m => m.SettingsComponent)
}
];A clean pattern for automatically unsubscribing from Observables when a component is destroyed.
export class DataComponent implements OnInit, OnDestroy {
private destroy$ = new Subject<void>();
ngOnInit() {
this.dataService.getData().pipe(
takeUntil(this.destroy$)
).subscribe(data => this.data = data);
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}Bootstrapping an entire app from one standalone root component, with router and HTTP client providers.
import { bootstrapApplication } from '@angular/platform-browser';
import { provideRouter } from '@angular/router';
import { provideHttpClient } from '@angular/common/http';
import { AppComponent } from './app/app.component';
import { routes } from './app/app.routes';
bootstrapApplication(AppComponent, {
providers: [provideRouter(routes), provideHttpClient()]
});Continue Your Angular Interview Preparation
Angular developers are commonly asked questions on TypeScript, JavaScript, RxJS, HTML, CSS, REST APIs, Git, and software engineering fundamentals. Strengthening these complementary skills can significantly improve your interview performance.
Angular Career Opportunities
Angular is one of the most popular front-end frameworks for enterprise web application development. It is widely adopted by startups, multinational corporations, financial institutions, healthcare organizations, government agencies, and software service companies for building scalable single-page applications.
Professionals with strong Angular knowledge often work as Front-End Developers, Angular Developers, Full Stack Developers, UI Engineers, Software Engineers, Technical Leads, and Application Architects. Learning Angular together with TypeScript, REST APIs, RxJS, and state management libraries greatly improves career opportunities.
Angular Interview Preparation Tips
- Master Angular fundamentals including components, modules, directives, pipes, and services.
- Practice dependency injection, routing, guards, interceptors, and lazy loading.
- Understand RxJS Observables, Subjects, operators, and asynchronous programming.
- Revise Angular Forms including Template-driven Forms and Reactive Forms.
- Learn Angular Signals, standalone components, and the latest Angular features introduced in recent releases.
- Build multiple real-world Angular applications to confidently answer practical interview questions.
About This Angular Interview Guide
This interview guide is designed to help students, freshers, experienced professionals, and software engineers prepare for Angular interviews through structured learning. The questions are organized from beginner to advanced level and include practical explanations to improve conceptual understanding rather than memorization.
Since interview patterns vary across organizations, candidates should combine these interview questions with hands-on Angular projects, coding practice, TypeScript knowledge, and problem-solving exercises for the best interview results.