54 questions - Beginner to advanced

Angular interview questions and answers

Angular interviews go deeper than React ones, because the framework has more built-in parts. The questions that usually decide the result are change detection, dependency injection, RxJS inside services, and forms.

Last updated:

Angular basics

What is Angular?

Angular is a complete frontend framework from Google, written in TypeScript. Unlike a library, it already includes routing, HTTP, forms, dependency injection and testing. So a big team does not have to pick and join those pieces itself.

What is the difference between AngularJS and Angular?

AngularJS is the old 1.x version, written in JavaScript, with scopes, controllers and dirty checking. Angular from version 2 is a full rewrite in TypeScript, with components, a real dependency injection system and much better speed. The two are not compatible.

What is a component?

A component is one piece of the screen. It has a TypeScript class for the logic, an HTML template for the view, and CSS for the style. The @Component decorator joins them. Every Angular app is a tree of components that starts at the root.

@Component({
  selector: "app-user-card",
  standalone: true,
  template: `<h3>{{ name }}</h3>`,
})
export class UserCardComponent {
  @Input() name = "";
}

What is a module (NgModule)?

An NgModule groups components, directives, pipes and providers that belong together. It says what they can use and what they give to others. Modern Angular prefers standalone components, where each component lists its own imports, so NgModules are becoming optional.

What is a standalone component?

A standalone component belongs to no NgModule. It sets standalone: true and imports what it needs directly. That removes a whole layer of extra code and makes it possible to lazy load a single component.

What is a directive and what types are there?

A directive adds behaviour to an element that already exists. Structural directives change the DOM layout and start with a star, like *ngIf and *ngFor. Attribute directives change look or behaviour, like ngClass and ngStyle. A component is really a directive with a template.

What is data binding in Angular?

There are four kinds. Interpolation {{ value }} puts data into the template. Property binding [prop] sends data down. Event binding (click) sends events up. Two-way binding [(ngModel)] does both, and it is just the other two joined.

<input [value]="name" (input)="name = $event.target.value" />
<!-- same as -->
<input [(ngModel)]="name" />

What is the difference between a constructor and ngOnInit?

The constructor runs when the class is created. Use it only for dependency injection. ngOnInit runs after Angular has set the input properties. So read inputs and start your setup work there.

What are the lifecycle hooks in order?

ngOnChanges when an input changes. ngOnInit once after the first inputs. ngDoCheck on every check. ngAfterContentInit and ngAfterContentChecked for projected content. ngAfterViewInit and ngAfterViewChecked for the view and child views. ngOnDestroy just before the component is removed.

What do you do in ngOnDestroy?

Clean up. Unsubscribe from manual subscriptions, clear intervals, remove event listeners and disconnect observers. Skipping this is the most common cause of memory leaks in Angular apps.

What is content projection and ng-content?

Content projection lets a parent pass markup into the template of a child component. It is the Angular version of React children. Use a select attribute to send different pieces into different slots.

<!-- card.component.html -->
<div class="card">
  <header><ng-content select="[card-title]"></ng-content></header>
  <ng-content></ng-content>
</div>

What is the difference between ng-template, ng-container and ng-content?

ng-template holds markup that is not rendered until something asks for it. Structural directives use it. ng-container is an invisible group. It lets you apply a directive without adding a real DOM node. ng-content is the slot where content from the parent appears.

What is the AsyncPipe and why is it recommended?

The AsyncPipe subscribes to an Observable in the template, shows the latest value, and unsubscribes on its own when the component is destroyed. That removes a whole group of memory leak bugs, so it is the preferred way to use observables in a view.

<div *ngIf="user$ | async as user">{{ user.name }}</div>

Dependency injection and services

What is dependency injection?

With dependency injection, a class does not create the things it needs. Angular creates them and passes them in. That makes classes easier to test, because you can pass a fake service. It also makes them easier to reuse, because the class does not care where the dependency came from.

@Injectable({ providedIn: "root" })
export class UserService {
  constructor(private http: HttpClient) {}
}

// in a component
constructor(private users: UserService) {}
// or the modern form
private users = inject(UserService);

What does providedIn: "root" mean?

The service is registered once for the whole app. One shared instance is created the first time something injects it. It is also tree-shakable: if nothing uses the service, it is dropped from the bundle.

What is the difference between providing a service in root and in a component?

In root there is one instance for the whole app, so the state is shared. Provided in a component, a new instance is created for each instance of that component and destroyed with it. That is useful for state that belongs to one form or one widget.

What is an injection token?

An injection token is a unique key used to inject something that is not a class, such as a settings object or a string. You create it with new InjectionToken and then provide a value for it.

export const API_URL = new InjectionToken<string>("API_URL");
// provide: { provide: API_URL, useValue: "https://api.example.com" }

What is the difference between useClass, useValue, useFactory and useExisting?

useClass creates a class. useValue gives a ready value. useFactory calls a function that builds the value and can use other services. useExisting makes a new token point at a provider that already exists.

What is an HTTP interceptor?

An interceptor is code that sees every request going out and every response coming in. It is the right place to add an auth token, log timings, show a global loader or retry on failure, without touching each service.

export const authInterceptor: HttpInterceptorFn = (req, next) => {
  const token = inject(AuthService).token;
  return next(req.clone({ setHeaders: { Authorization: "Bearer " + token } }));
};

Why does HttpClient return an Observable and not a Promise?

Because an Observable can be cancelled, retried and joined with operators, and it can emit more than once. Cancelling matters a lot for search as you type, where switchMap drops the earlier request on its own.

Do you have to unsubscribe from HttpClient?

HttpClient completes after one value, so it cleans itself up. Still cancel it when the component is destroyed if the request is slow. The AsyncPipe or takeUntilDestroyed does that for you.

Change detection and performance

The section that separates senior candidates.

What is change detection in Angular?

After anything that could change data - a click, a timer, an HTTP response - Angular walks the component tree. It checks whether the values used in each template changed, then updates the DOM where needed.

What is Zone.js?

Zone.js is a library that patches browser APIs like setTimeout, addEventListener and XHR. That is how Angular knows an async job finished and change detection should run. Newer Angular can run zoneless and use signals to know exactly what changed.

What is the difference between Default and OnPush change detection?

With Default, Angular checks the component whenever anything anywhere might have changed. With OnPush, it checks only when an input reference changes, an event fires inside the component, an observable used with the AsyncPipe emits, or you mark it by hand. OnPush plus data you never mutate is the standard fix for speed.

@Component({
  selector: "app-row",
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `{{ row.name }}`,
})
export class RowComponent {
  @Input() row!: Row;
}

Why does OnPush break when you mutate an object?

Because OnPush compares input references. If you change a property inside the same object, the reference is the same, so Angular skips the check and the screen does not update. Replace the object instead of changing it.

What is markForCheck versus detectChanges?

markForCheck marks this component and its parents as dirty, so they are checked in the next cycle. detectChanges runs change detection on this component right now. detach stops checking a component at all.

What is trackBy in *ngFor and why use it?

Without trackBy, Angular tells list items apart by object reference. A fresh array from the server then rebuilds every row. trackBy tells Angular to compare by id, so only the real changes are rendered again.

<li *ngFor="let user of users; trackBy: trackById">{{ user.name }}</li>

trackById(index: number, user: User) { return user.id; }

Why should you avoid calling a function in a template?

Because it runs on every change detection cycle, which can be hundreds of times a second. Use a pure pipe, a computed signal, or work the value out once in the class.

What is the difference between a pure and an impure pipe?

A pure pipe runs only when its input reference changes, so it is cheap. An impure pipe runs on every change detection cycle, which is slow, so it should be rare.

What is AOT compilation?

AOT means Ahead-of-Time. Templates are turned into JavaScript during the build instead of in the browser. The app starts faster, the bundle is smaller because the compiler is not shipped, and template errors are caught at build time. It is the default for production builds.

How do you make an Angular app faster?

Lazy load feature routes. Use OnPush with data you never mutate. Add trackBy to lists. Do not call functions in templates. Virtualise long lists with the CDK. Use the AsyncPipe instead of manual subscriptions. Check the bundle with the build analyser.

Forms

What is the difference between template-driven and reactive forms?

Template-driven forms are built in the HTML with ngModel. They are quick for small forms, but the logic hides in the template. Reactive forms are built in the TypeScript class with FormControl and FormGroup. They are clear, easy to test, and better for big or dynamic forms.

form = new FormGroup({
  email: new FormControl("", [Validators.required, Validators.email]),
  password: new FormControl("", Validators.minLength(8)),
});

What is a FormControl, FormGroup and FormArray?

A FormControl is one field with a value, a validation state and events. A FormGroup is an object of controls. A FormArray is a list of controls, used when the user can add rows.

How do you write a custom validator?

A validator is a function that takes the control and returns null when the value is valid, or an object that describes the error. An async validator returns an Observable or Promise of the same thing.

export function noSpaces(control: AbstractControl) {
  return control.value?.includes(" ") ? { noSpaces: true } : null;
}

What is the difference between touched, dirty and pristine?

touched means the field was focused and then left. dirty means the user changed the value. pristine is the opposite of dirty. Error messages usually show only when the control is invalid and also touched or dirty.

What is valueChanges and how do you use it well?

valueChanges is an Observable that emits every time the value changes. Add debounceTime and distinctUntilChanged before calling an API. Without them you fire a request on every key press.

this.form.controls.search.valueChanges.pipe(
  debounceTime(300),
  distinctUntilChanged(),
  switchMap((q) => this.api.search(q))
).subscribe();

What is a ControlValueAccessor?

It is the interface that lets your own component act like a native form control, so it works with ngModel and formControlName. You implement writeValue, registerOnChange, registerOnTouched and setDisabledState.

What is the difference between setValue and patchValue?

setValue needs every control in the group and throws if one is missing, which catches mistakes. patchValue updates only the keys you give and leaves the rest alone.

Routing

How does Angular routing work?

You write an array of routes that map a path to a component. The router watches the URL and renders the matching component inside <router-outlet>. Order matters, because the first match wins.

export const routes: Routes = [
  { path: "", component: HomeComponent },
  { path: "users/:id", component: UserComponent },
  { path: "**", component: NotFoundComponent },
];

What is lazy loading in Angular?

Lazy loading means the bundle for a feature is downloaded only when the user goes there, using loadComponent or loadChildren. It keeps the first download small, which matters most on slow connections.

{ path: "admin", loadComponent: () => import("./admin/admin.component").then((m) => m.AdminComponent) }

What is a route guard?

A guard is a function that runs before navigation and returns true, false or a redirect. CanActivate protects a page. CanDeactivate warns about unsaved changes. A resolver loads data before the route opens.

export const authGuard: CanActivateFn = () => {
  const auth = inject(AuthService);
  return auth.isLoggedIn() || inject(Router).createUrlTree(["/login"]);
};

What is the difference between ActivatedRoute snapshot and observables?

The snapshot gives the value once. The params and queryParams observables keep emitting. That matters when the user moves from /users/1 to /users/2 and Angular reuses the component instead of creating a new one.

What is the difference between a route parameter and a query parameter?

A route parameter is part of the path and usually names a resource, like /users/42. A query parameter comes after the question mark and usually carries optional filters, like ?page=2&sort=name.

What is a resolver?

A resolver is a function that loads data before the route opens, so the component renders with data instead of an empty state. The trade-off is that navigation feels slower.

Signals and modern Angular

What is a signal?

A signal is a value that knows who reads it. When it changes, only the places that really use it are updated. There is no walking of the whole tree. It makes change detection exact and is the base of zoneless Angular.

count = signal(0);
double = computed(() => this.count() * 2);

increment() { this.count.update((c) => c + 1); }

What is the difference between signal, computed and effect?

signal holds a value you can write to. computed builds a value from other signals and caches it until they change. effect runs side effects when the signals it reads change. Do not use an effect to set other signals.

What is the difference between a signal and an Observable?

A signal always has a current value that you can read at once, and it is meant for state. An Observable is a stream over time that may emit zero or many values, and it is meant for events and async work. Both can live together: toSignal and toObservable convert between them.

What is the new control flow syntax?

Angular now has template blocks built in: @if, @for, @switch and @defer. They replace *ngIf and *ngFor. They are faster, need no import, and @for requires a track expression, which prevents the missing-trackBy speed bug.

@if (user(); as u) {
  <p>{{ u.name }}</p>
} @else {
  <p>Loading...</p>
}

@for (item of items(); track item.id) {
  <li>{{ item.name }}</li>
}

What does @defer do?

@defer delays loading a block of the template and its JavaScript until a condition is met. The block can wait until it enters the screen, until the user interacts, or until the browser is idle. It is lazy loading at template level.

What is takeUntilDestroyed?

It is an RxJS operator from Angular that ends a subscription on its own when the component or service is destroyed. It replaces the old destroy$ Subject pattern.

this.service.data$
  .pipe(takeUntilDestroyed())
  .subscribe((data) => this.rows = data);

What is Angular Universal / SSR?

It means rendering the app on the server, so the browser gets real HTML on the first load. The page feels faster and SEO improves. Watch out for code that uses window or document, because they do not exist on the server.

What is ViewChild and ContentChild?

ViewChild gets a reference to an element or component in this component's own template. It is ready from ngAfterViewInit. ContentChild gets one from the content that a parent projected in. It is ready from ngAfterContentInit.

How do you share data between unrelated components?

Use a service that holds the state, exposed as a signal or a BehaviorSubject, and inject it into both components. For a large app with complex flows, a state library such as NgRx does the same job with more structure.

How do you test an Angular component?

Use TestBed to set up a testing module. Create the component fixture, call detectChanges, then check the rendered DOM. Replace real services with spies or stubs so the tests stay fast and give the same result every time.

Continue with another topic

Practise live

CrackInterviewAI listens to the live interview and gives a structured answer on screen for coding, system design, HR and project questions. Download for Windows.