Title: Angular Framework — LearnCoachAssist

Q: What is Angular?
A: Angular is a TypeScript-based front-end framework developed by Google for building dynamic, single-page applications (SPAs). It provides a comprehensive solution including components, services, routing, and dependency injection out of the box.

Q: What is an Angular component?
A: A component is the fundamental building block of an Angular application. It consists of:
- A TypeScript class decorated with @Component()
- An HTML template
- Optional CSS styles
- Metadata such as selector, templateUrl, and styleUrls

Q: What is the purpose of the @Component decorator?
A: The @Component() decorator marks a class as an Angular component and provides metadata that tells Angular how to process, instantiate, and use the component at runtime. Key properties include:
- selector – the custom HTML tag
- templateUrl – path to the HTML template
- styleUrls – array of stylesheets

Q: What is data binding in Angular?
A: Data binding is a mechanism that connects the component class to the template. Angular supports four forms:
- Interpolation: {{ expression }}
- Property binding: [property]="expression"
- Event binding: (event)="handler()"
- Two-way binding: [(ngModel)]="property"

Q: What is an Angular service?
A: A service is a class decorated with @Injectable() that encapsulates reusable business logic, data access, or utility functions. Services are typically singletons when provided at the root level and are shared across components via dependency injection.

Q: What is dependency injection (DI) in Angular?
A: Dependency injection is a design pattern where Angular's DI system creates and delivers dependencies (usually services) to classes that request them. Instead of a class creating its own dependencies, they are injected via the constructor:
constructor(private myService: MyService) {}

Q: What is the purpose of the @Injectable decorator?
A: The @Injectable() decorator marks a class as available for Angular's dependency injection system. Setting @Injectable({ providedIn: 'root' }) registers the service as a singleton at the application root level, enabling tree-shaking.

Q: What is an Angular module (NgModule)?
A: An NgModule is a class decorated with @NgModule() that organizes related code into cohesive blocks. Key metadata properties:
- declarations – components, directives, pipes
- imports – other modules needed
- providers – services
- bootstrap – root component

Q: What is the difference between declarations and imports in @NgModule?
A: declarations registers components, directives, and pipes that belong to the current module.
imports brings in other NgModules whose exported classes are needed by templates in this module. For example, importing FormsModule to use ngModel.

Q: What are Angular lifecycle hooks?
A: Lifecycle hooks are methods that Angular calls at specific moments in a component's life. Key hooks in order:
- ngOnChanges() – input property changes
- ngOnInit() – after first ngOnChanges
- ngDoCheck() – custom change detection
- ngAfterViewInit() – after view initializes
- ngOnDestroy() – before component is destroyed

Q: What is ngOnInit and when is it called?
A: ngOnInit() is a lifecycle hook called once after the first ngOnChanges(). It is used for component initialization logic such as fetching data from a service. It is preferred over the constructor for initialization because input bindings are available at this point.

Q: What is ngOnDestroy used for?
A: ngOnDestroy() is called just before Angular destroys the component. It is used for cleanup tasks such as:
- Unsubscribing from Observables
- Detaching event handlers
- Stopping timers with clearInterval()
This prevents memory leaks.

Q: What is Angular routing?
A: Angular routing maps URL paths to components, enabling navigation in a single-page application without full page reloads. Routes are defined in a Routes array and loaded via RouterModule.forRoot(routes). The <router-outlet> directive marks where routed components render.

Q: How do you define routes in Angular?
A: Routes are defined as an array of Route objects:
const routes: Routes = [
  { path: 'home', component: HomeComponent },
  { path: 'users/:id', component: UserComponent },
  { path: '**', component: NotFoundComponent }
];
The ** wildcard handles unmatched routes.

Q: What is lazy loading in Angular?
A: Lazy loading delays the loading of a feature module until the user navigates to its route. This reduces the initial bundle size. It is configured with:
{ path: 'admin', loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule) }

Q: What is a route guard in Angular?
A: A route guard is a service that controls whether navigation to or from a route is allowed. Common guard interfaces:
- CanActivate – controls access to a route
- CanDeactivate – controls leaving a route
- CanLoad – controls lazy-loaded module loading
- Resolve – pre-fetches data before activation

Q: How does CanActivate guard work?
A: CanActivate is a guard that runs before a route is activated. It returns a boolean, UrlTree, or an Observable/Promise of these. If it returns false, navigation is cancelled. Example use: checking if a user is authenticated before allowing access to a protected route.

Q: What is the difference between template-driven and reactive forms?
A: Template-driven forms use directives like ngModel in the template and are simpler for basic forms.
Reactive forms use FormGroup and FormControl in the component class, offering more control, easier testing, and better handling of dynamic or complex forms. Reactive forms require importing ReactiveFormsModule.

Q: How do you create a reactive form in Angular?
A: Create a reactive form using FormGroup and FormControl:
this.myForm = new FormGroup({
  name: new FormControl('', Validators.required),
  email: new FormControl('', [Validators.required, Validators.email])
});
Bind it in the template with [formGroup]="myForm" and formControlName="name".

Q: What is FormBuilder in Angular?
A: FormBuilder is an injectable service that provides a shorthand syntax for creating FormGroup, FormControl, and FormArray instances:
this.myForm = this.fb.group({
  name: ['', Validators.required],
  email: ['', [Validators.required, Validators.email]]
});

Q: What are Angular pipes?
A: Pipes are functions that transform data in templates. They are used with the | operator:
{{ birthday | date:'longDate' }}
Built-in pipes include DatePipe, UpperCasePipe, LowerCasePipe, CurrencyPipe, DecimalPipe, JsonPipe, and AsyncPipe.

Q: How do you create a custom pipe?
A: Create a class decorated with @Pipe({ name: 'myPipe' }) that implements the PipeTransform interface:
@Pipe({ name: 'truncate' })
export class TruncatePipe implements PipeTransform {
  transform(value: string, limit: number): string {
    return value.length > limit ? value.substring(0, limit) + '...' : value;
  }
}

Q: What is the AsyncPipe?
A: The AsyncPipe automatically subscribes to an Observable or Promise and returns the emitted value in the template:
{{ data$ | async }}
It also automatically unsubscribes when the component is destroyed, preventing memory leaks. It triggers change detection when a new value is emitted.

Q: What are Angular directives?
A: Directives are classes that add behavior to elements in the DOM. There are three types:
- Component directives – directives with a template (components)
- Structural directives – change DOM layout (e.g., *ngIf, *ngFor)
- Attribute directives – change appearance or behavior (e.g., ngClass, ngStyle)

Q: What is the *ngIf directive?
A: *ngIf is a structural directive that conditionally includes or removes an element from the DOM based on a boolean expression:
<div *ngIf="isLoggedIn; else loginTemplate">Welcome!</div>
<ng-template #loginTemplate>Please log in.</ng-template>
Unlike hiding with CSS, *ngIf completely removes the element and its children.

Q: What is the *ngFor directive?
A: *ngFor is a structural directive that repeats a template for each item in a collection:
<li *ngFor="let item of items; let i = index; trackBy: trackByFn">
  {{ i }}: {{ item.name }}
</li>
Using trackBy improves performance by helping Angular identify which items changed.

Q: How do you create a custom attribute directive?
A: Create a class decorated with @Directive({ selector: '[appHighlight]' }):
@Directive({ selector: '[appHighlight]' })
export class HighlightDirective {
  @HostListener('mouseenter') onMouseEnter() {
    this.el.nativeElement.style.backgroundColor = 'yellow';
  }
  constructor(private el: ElementRef) {}
}

Q: What is RxJS in Angular?
A: RxJS (Reactive Extensions for JavaScript) is a library for reactive programming using Observables. Angular relies heavily on RxJS for:
- HTTP requests via HttpClient
- Reactive forms value changes
- Router events
- Event handling
Key concepts include Observable, Observer, Subject, and operators.

Q: What is an Observable in RxJS?
A: An Observable represents a stream of data that arrives over time. Unlike Promises, Observables are lazy (they don't execute until subscribed to), can emit multiple values, and are cancellable via unsubscribe():
this.myService.getData().subscribe({
  next: data => console.log(data),
  error: err => console.error(err)
});

Q: What is the difference between Observable and Promise?
A: Key differences:
- Observable emits multiple values over time; Promise resolves once
- Observable is lazy (executes on subscribe); Promise is eager (executes immediately)
- Observable is cancellable via unsubscribe(); Promise is not
- Observable supports operators like map, filter, switchMap

Q: What is a Subject in RxJS?
A: A Subject is both an Observable and an Observer. It can multicast values to multiple subscribers. Variants include:
- BehaviorSubject – stores the latest value and emits it to new subscribers
- ReplaySubject – replays a specified number of past emissions
- AsyncSubject – emits only the last value upon completion

Q: What are common RxJS operators used in Angular?
A: Common RxJS operators:
- map – transforms emitted values
- filter – filters emissions by condition
- switchMap – switches to a new inner Observable, cancelling the previous
- mergeMap – maps to inner Observable, subscribes concurrently
- tap – performs side effects without modifying the stream
- catchError – handles errors in the stream

Q: What is the switchMap operator?
A: switchMap maps each emission to an inner Observable and switches to the latest one, unsubscribing from previous inner Observables. Common use case: search-as-you-type where each keystroke triggers a new HTTP request, and previous pending requests are automatically cancelled.

Q: What is HttpClient in Angular?
A: HttpClient is a service in @angular/common/http for making HTTP requests. It returns Observables and supports:
- get(), post(), put(), delete()
- Typed responses with generics
- Request/response headers
- Query parameters
- Progress events
Import HttpClientModule to use it.

Q: How do you make a GET request with HttpClient?
A: Use the get() method with a generic type:
this.http.get<User[]>('/api/users').subscribe({
  next: users => this.users = users,
  error: err => console.error('Failed:', err)
});
The request is executed only when subscribed to, as HttpClient returns a cold Observable.

Q: What is an HTTP interceptor in Angular?
A: An HTTP interceptor is a service implementing HttpInterceptor that intercepts and optionally transforms HTTP requests and responses. Common use cases:
- Adding authentication tokens to headers
- Logging requests and responses
- Global error handling
- Showing/hiding a loading spinner

Q: How do you create an HTTP interceptor?
A: Implement the HttpInterceptor interface:
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const cloned = req.clone({ setHeaders: { Authorization: 'Bearer ' + this.token } });
    return next.handle(cloned);
  }
}
Register it in providers with HTTP_INTERCEPTORS multi-token.

Q: What is the @Input decorator?
A: @Input() marks a component property as an input binding, allowing a parent component to pass data to a child:
Child: @Input() name: string;
Parent template: <app-child [name]="userName"></app-child>
Changes to the parent value automatically propagate to the child.

Q: What is the @Output decorator?
A: @Output() marks a property as an event emitter that sends data from a child to a parent component:
Child: @Output() notify = new EventEmitter<string>();
Child method: this.notify.emit('Hello');
Parent template: <app-child (notify)="onNotify($event)"></app-child>

Q: What is ViewChild in Angular?
A: @ViewChild() is a decorator that provides access to a child component, directive, or DOM element from the parent component class:
@ViewChild(ChildComponent) child: ChildComponent;
or for a template reference:
@ViewChild('myInput') inputRef: ElementRef;
It is available after the ngAfterViewInit() lifecycle hook.

Q: What is ContentChild vs ViewChild?
A: @ViewChild queries elements in the component's own template.
@ContentChild queries elements in the component's projected content (content placed between the component's tags via <ng-content>).
ViewChild is available after ngAfterViewInit(); ContentChild is available after ngAfterContentInit().

Q: What is ng-content used for?
A: <ng-content> enables content projection, allowing a parent to insert content into a child component's template:
Child template: <div class="card"><ng-content></ng-content></div>
Parent usage: <app-card><p>Projected content here</p></app-card>
It supports multi-slot projection with the select attribute.

Q: What is change detection in Angular?
A: Change detection is Angular's mechanism for keeping the view in sync with the component's data. By default, Angular uses a zone-based strategy that checks all components from root to leaves on every event. You can optimize with ChangeDetectionStrategy.OnPush, which only checks when @Input() references change or events are triggered.

Q: What is the OnPush change detection strategy?
A: ChangeDetectionStrategy.OnPush tells Angular to check the component only when:
- An @Input() reference changes (not mutations)
- An event originates from the component or its children
- An Observable linked with AsyncPipe emits
- markForCheck() is called manually
This significantly improves performance for large apps.

Q: What is Angular CLI?
A: The Angular CLI (ng) is a command-line tool for scaffolding and managing Angular projects. Key commands:
- ng new – create a new project
- ng generate component/service/module – generate code
- ng serve – start a dev server
- ng build – build for production
- ng test – run unit tests

Q: What is the purpose of environment files in Angular?
A: Environment files (environment.ts and environment.prod.ts) store configuration values that differ between environments, such as API URLs and feature flags. Angular CLI automatically swaps the file during build:
export const environment = {
  production: false,
  apiUrl: 'http://localhost:3000'
};

Q: What are Angular standalone components?
A: Standalone components (Angular 14+) are components that don't need to be declared in an NgModule. They declare their own dependencies via the imports array in @Component():
@Component({
  standalone: true,
  imports: [CommonModule],
  ...
})
This simplifies the module structure and enables tree-shakable applications.

Q: What is the Angular Router's ActivatedRoute?
A: ActivatedRoute is an injectable service that provides information about the current route:
- params – Observable of route parameters
- queryParams – Observable of query parameters
- data – Observable of resolved data
- snapshot – non-Observable static snapshot
Usage: this.route.params.subscribe(p => this.id = p['id']);

Q: What is a Resolver in Angular routing?
A: A Resolver is a service implementing Resolve<T> that pre-fetches data before a route is activated. The resolved data is available via ActivatedRoute.data. This ensures the component has its required data before rendering, avoiding empty states or loading indicators on initial display.

Q: What is the difference between forRoot and forChild?
A: RouterModule.forRoot(routes) is used once in the root module to configure the router with the main routes and register the Router service.
RouterModule.forChild(routes) is used in feature modules to register additional routes without re-providing the Router service. Using forRoot more than once causes unexpected behavior.

Q: What is a Signal in Angular?
A: A Signal is a reactive primitive introduced in Angular 16 that wraps a value and notifies interested consumers when the value changes:
const count = signal(0);
count.set(1);
count.update(v => v + 1);
Reading count() inside a template, computed(), or effect() automatically tracks the dependency.

Q: What is the difference between signal() and BehaviorSubject?
A: Key differences:
- signal() is synchronous and accessed by calling it as a function: count()
- BehaviorSubject is an RxJS Observable that requires subscribe() and works with operators
- Signals integrate with Angular's change detection automatically; BehaviorSubject needs async pipe or markForCheck()
- BehaviorSubject supports operators like debounceTime; signals do not natively
Use toSignal() / toObservable() to interoperate.

Q: What is the computed() function?
A: computed() creates a derived signal whose value is automatically recalculated when any of its tracked signal dependencies change:
const fullName = computed(() => firstName() + ' ' + lastName());
computed() is lazy and memoized: it only recomputes when read AND a dependency has changed.

Q: What is the effect() function?
A: effect() runs a side-effecting function whenever any signal it reads changes:
effect(() => console.log('count is', count()));
Effects run asynchronously via the microtask queue, after Angular's change detection. Effects must be created in an injection context (constructor or with an explicit { injector } option) unless { manualCleanup: true } is set.

Q: What does untracked() do?
A: untracked() lets you read signals without creating a dependency:
effect(() => {
  const id = untracked(() => selectedId());
  fetchData(id);
});
This prevents the effect from re-running when selectedId changes. Useful for reading "current" values inside handlers.

Q: What is the new built-in control flow in Angular 17?
A: Angular 17 introduced block control flow that replaces *ngIf, *ngFor, and *ngSwitch with native template syntax:
- @if (cond) { ... } @else { ... }
- @for (item of items; track item.id) { ... }
- @switch (val) { @case (x) { ... } @default { ... } }
It is faster, has built-in track, empty, and requires no imports of CommonModule.

Q: Why does @for require a track expression?
A: @for requires a track expression to identify items uniquely across renders:
@for (user of users; track user.id) { ... }
Without track, Angular throws a compile-time error. A good track function avoids unnecessary DOM re-creation, mirroring trackBy in *ngFor.

Q: What does @empty do in @for?
A: The @empty block renders content when the iterable is empty:
@for (item of items; track item.id) {
  {{ item.name }}
} @empty {
  No items found.
}
It eliminates the need for a separate *ngIf="items.length === 0" block.

Q: What is the @let block in Angular 18?
A: @let declares a local template variable scoped to the surrounding block:
@let discounted = price() * 0.9;
{{ discounted }}
It supports arbitrary expressions, is reactive (re-evaluates when signals it reads change), and cannot be reassigned. Useful for computed display values without a computed() in the component class.

Q: What is Angular's deferrable view (@defer)?
A: @defer lazily loads template content only when a trigger fires:
@defer (on viewport) {
  <heavy-chart></heavy-chart>
} @placeholder { <div>Loading...</div> }
@loading (minimum 200ms) { <spinner></spinner> }
@error { <p>Failed to load</p> }
It enables fine-grained code-splitting per template block, beyond route-level lazy loading.

Q: What are the @defer trigger options?
A: Common @defer triggers:
- on viewport(ref) – when element scrolls into view
- on idle – after browser is idle
- on immediate – right after render
- on timer(Xms) – after delay
- on interaction(ref) – on click/focus
- on hover(ref) – on mouse hover
- when condition() – when a condition is truthy
Triggers can be combined with ;: on viewport; on idle.

Q: What is the inject() function and why use it over constructor injection?
A: inject() is a function that retrieves a dependency from the active injection context without using a constructor:
private http = inject(HttpClient);
Advantages:
- Works in functional guards, interceptors, and factory providers that aren't classes
- Allows conditional injection
- Enables cleaner code without boilerplate constructors
It must be called in an injection context unless given an explicit Injector.

Q: What is an InjectionToken?
A: An InjectionToken<T> creates a non-class DI token for injecting values, interfaces, or primitives:
export const API_URL = new InjectionToken<string>('API_URL');
Provide it:
{ provide: API_URL, useValue: 'https://api.example.com' }
Consume it:
constructor(@Inject(API_URL) private url: string) {}
Use factory: for computed values and dependencies.

Q: What are the provider definition functions (useValue, useClass, useFactory, useExisting)?
A: Provider configuration options:
- useValue – provides a literal value: { provide: TOKEN, useValue: 42 }
- useClass – provides an instance of a class: { provide: Logger, useClass: ConsoleLogger }
- useFactory – uses a function to create the value: { provide: SERVICE, useFactory: () => new Service(inject(HttpClient)) }
- useExisting – aliases an existing token: { provide: NewLogger, useExisting: OldLogger }

Q: What is a multi-provider token?
A: A multi-provider allows multiple values to be associated with a single token. Use multi: true:
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
Angular collects all such providers into an array. Built-in examples include HTTP_INTERCEPTORS, ROUTER_CONFIGURATION_EXTRA, NG_VALIDATORS, and NG_VALUE_ACCESSOR.

Q: What is the difference between @Self, @SkipSelf, @Optional, and @Host?
A: Modifier decorators control where Angular looks for a dependency:
- @Self() – only the current injector
- @SkipSelf() – start search from parent injector
- @Optional() – inject null instead of throwing if not found
- @Host() – stop search at the host component
Example:
constructor(@SkipSelf() @Optional() private parent: ParentService) {}

Q: What is forwardRef and when is it needed?
A: forwardRef(() => SomeClass) resolves a class reference later, allowing you to reference a class that is not yet defined at the point of use:
constructor(@Inject(forwardRef(() => MyService)) svc: MyService) {}
Common when classes reference each other (e.g., parent/child components in the same file).

Q: What is a hierarchical injector in Angular?
A: Angular has a tree of injectors parallel to the component tree. When a component lists a provider in providers: [], that provider creates a new injector for that component and its descendants. Services not provided there resolve up the tree. This enables scoped instances, e.g., one UserService per feature module.

Q: What are viewProviders vs providers?
A: providers is visible to the component and its content children (projected content).
viewProviders is visible only to the component's own view (template + view children), not to projected content.
Use viewProviders when a service must not leak into content that the parent may project in.

Q: What is the inject() function's behavior outside an injection context?
A: Outside an injection context, inject() throws unless you pass an explicit Injector:
const svc = inject(MyService, { optional: true });
To call it from outside, capture an Injector via inject(Injector) and then call injector.get(MyService), or use runInInjectionContext(injector, () => inject(MyService)).

Q: What is bootstrapApplication in Angular?
A: bootstrapApplication(AppComponent, appConfig) replaces the @NgModule-based bootstrapModule() flow for standalone apps:
bootstrapApplication(AppComponent, {
  providers: [
    provideRouter(routes),
    provideHttpClient(withInterceptors([authInterceptor]))
  ]
});
It is the standard bootstrap for fully standalone Angular 17+ apps.

Q: What is provideRouter() and how does it differ from RouterModule.forRoot?
A: provideRouter(routes, withComponentInputBinding(), withViewTransitions()) is the standalone-friendly provider for routing. It replaces RouterModule.forRoot() and accepts feature functions like:
- withComponentInputBinding() – binds route params to @Input()
- withViewTransitions() – enables View Transitions API
- withInMemoryScrolling() – scroll restoration
- withHashLocation() – hash-based routing
It avoids NgModule boilerplate.

Q: What is withInterceptors() in standalone HttpClient?
A: provideHttpClient(withInterceptors([authInterceptor, loggingInterceptor])) replaces the HTTP_INTERCEPTORS-based approach. Interceptors are now simple functions:
export const authInterceptor: HttpInterceptorFn = (req, next) => {
  const token = inject(AuthService).token();
  return next(req.clone({ setHeaders: { Authorization: 'Bearer ' + token }}));
}
This is the canonical modern pattern.

Q: What is a functional route guard?
A: A functional guard is a plain function using inject() instead of a class:
export const authGuard: CanActivateFn = () => {
  return inject(AuthService).isLoggedIn() || inject(Router).parseUrl('/login');
};
Register on a route:
{ path: 'admin', canActivate: [authGuard], loadComponent: () => import('./admin.component') }
Functional guards integrate with inject(), signals, and the standalone API.

Q: What is CanMatch vs CanActivate?
A: CanMatch runs before route matching. If it returns false, the router tries the next route definition. Use it for feature flags or role-based route selection:
{ path: 'beta', canMatch: [betaEnabledGuard], component: BetaComponent }
CanActivate runs after matching and simply cancels navigation. Use CanMatch when you need conditional route resolution.

Q: What is withComponentInputBinding()?
A: withComponentInputBinding() enables automatic binding of route params, query params, and resolved data to component @Input() properties:
@Input() id!: string; // :id param
@Input() page!: number; // ?page= query param
This removes the need to inject ActivatedRoute for simple cases and integrates with signal inputs.

Q: What is CanDeactivate and how do you implement it?
A: CanDeactivate guards leaving a route, e.g., to warn about unsaved changes:
export const unsavedChangesGuard: CanDeactivateFn<HasFormComponent> = (component) => {
  return component.canDeactivate() ? true : confirm('Discard changes?');
};
Return true, false, UrlTree, or an Observable/Promise resolving to one.

Q: What is a router resolver and how do you write one functionally?
A: A resolver pre-fetches data before the route activates:
export const userResolver: ResolveFn<User> = (route) => {
  const id = route.paramMap.get('id')!;
  return inject(UserService).getById(id);
};
Attach: { path: 'user/:id', resolve: { user: userResolver }, component: UserComponent }
Read with route.data or route.snapshot.data.

Q: What is the difference between ActivatedRoute snapshot and Observable?
A: route.snapshot returns the value at the moment of access, and does not update if the route changes without component recreation (e.g., navigating from /user/1 to /user/2 with runGuardsAndResolvers: 'paramsChange').
route.params is an Observable that emits on every change. Prefer Observables (or route.paramMap) when the component reuses across param values.

Q: What is paramMap vs params on ActivatedRoute?
A: params returns a { [key: string]: any } object with string keys.
paramMap returns a ParamMap with strongly typed get() and getAll() methods and a keys array. Prefer paramMap for type safety and clarity:
this.route.paramMap.subscribe(p => this.id = p.get('id'));

Q: What is runGuardsAndResolvers and what are its options?
A: runGuardsAndResolvers controls when guards/resolvers re-run on the same component:
- 'paramsChange' (default) – when path or query params change
- 'paramsOrQueryParamsChange' – also on query param changes
- 'always' – every navigation, even with no param changes
- 'pathParamsChange' – only path params, ignoring query params
Useful to keep the URL stable but refresh data.

Q: What are NavigationExtras?
A: NavigationExtras configure router.navigate:
- queryParams – { page: 2 }
- queryParamsHandling – 'merge' or 'preserve'
- fragment – e.g., 'section-1'
- state – arbitrary data available via history.state
- replaceUrl – replaces current history entry
- relativeTo – relative navigation base
Example: router.navigate(['users'], { queryParams: { page: 2 } });

Q: What are Router events?
A: Router emits events during navigation:
- NavigationStart
- RouteConfigLoadStart / RouteConfigLoadEnd
- RoutesRecognized
- GuardsCheckStart / GuardsCheckEnd
- ResolveStart / ResolveEnd
- NavigationEnd
- NavigationCancel, NavigationError
Listen via router.events for loading indicators or analytics.

Q: What is RouteReuseStrategy?
A: RouteReuseStrategy controls whether Angular destroys or reuses a component when navigating away and back. The default destroys it. Custom strategies enable tab-like persistence:
@Injectable()
export class CustomReuseStrategy extends RouteReuseStrategy {
  shouldReuseRoute() { return false; }
  store() { /* save detached handle */ }
  retrieve() { return null; }
}
Provide with { provide: RouteReuseStrategy, useClass: CustomReuseStrategy }.

Q: What is a PreloadingStrategy?
A: PreloadingStrategy decides when lazy-loaded modules load in the background after the app starts. Built-in: PreloadAllModules (loads all). Custom example:
export class SelectivePreload implements PreloadingStrategy {
  preload(route, load) { return route.data.preload ? load() : of(null); }
}
Apply via RouterModule.forRoot(routes, { preloadingStrategy: SelectivePreload }) or withPreloading(SelectivePreload).

Q: What is HashLocationStrategy?
A: By default, Angular uses PathLocationStrategy (HTML5 history API, e.g., /users). HashLocationStrategy uses URL fragments: /#/users. It avoids server-side rewrite requirements:
{ provide: LocationStrategy, useClass: HashLocationStrategy }
In standalone: provideRouter(routes, withHashLocation()).

Q: What is ViewEncapsulation and what modes exist?
A: ViewEncapsulation controls whether component styles leak out or are scoped:
- Emulated (default) – adds attribute selectors to scope styles
- None – global styles, no scoping
- ShadowDom – uses native Shadow DOM (requires browser support)
Set via @Component({ encapsulation: ViewEncapsulation.None }).

Q: What is the :host selector?
A: :host in component CSS targets the component's host element itself:
:host { display: block; }
Modifiers: :host(.active), :host-context(.dark) (matches an ancestor). Useful for layout primitives and theme-aware components.

Q: What is the difference between ng-container and ng-template?
A: <ng-container> is a logical grouping element that doesn't render in the DOM — useful with multiple structural bindings:
<ng-container *ngIf="x; else y">...</ng-container>
<ng-template> defines inert content not rendered until referenced (e.g., by *ngIf="...; else ngElse" or ViewContainerRef.createEmbeddedView). <ng-container> instantiates content; <ng-template> defines deferred content.

Q: What is ngTemplateOutlet?
A: ngTemplateOutlet renders an ng-template by reference:
<ng-container *ngTemplateOutlet="tpl; context: { $implicit: item, index: i }"></ng-container>
Inside the template, use let-item (implicit) and let-i="index". Great for reusable cell renderers in tables.

Q: What is ng-container vs ng-template vs ng-content?
A: - <ng-container> – non-rendering host for structural directives
- <ng-template> – defines a template, inert until instantiated
- <ng-content> – projects parent content into a child component's view
These three are easy to confuse; remember: container is grouping, template is deferred, content is projection.

Q: What is multi-slot content projection?
A: Multi-slot projection uses select on <ng-content>:
Child:
<ng-content select="[slot=header]"></ng-content>
<ng-content></ng-content>
<ng-content select="[slot=footer]"></ng-content>
Parent:
<app-card>
  <div slot="header">Title</div>
  Body
  <div slot="footer">©</div>
</app-card>

Q: What is ngProjectAs?
A: ngProjectAs re-maps projected content to a specific selector:
<app-card>
  <div *ngIf="hasHeader" ngProjectAs="[slot=header]">Header</div>
</app-card>
Useful when wrapping projected content in a structural directive that would otherwise break the selector matching.

Q: What is @HostBinding?
A: @HostBinding binds a host element property/class/style to a component property:
@HostBinding('class.active') isActive = false;
@HostBinding('attr.role') role = 'button';
Equivalent to declaring host: { '[class.active]': 'isActive' } in @Component.

Q: What is @HostListener?
A: @HostListener binds a host element event to a handler:
@HostListener('click', ['$event']) onClick(e: MouseEvent) { ... }
Equivalent to host: { '(click)': 'onClick($event)' }. Prefer using the host metadata for new code.

Q: What is Renderer2 vs direct DOM manipulation?
A: ElementRef.nativeElement bypasses Angular's view layer and breaks SSR/hydration. Renderer2 (inject or via @Directive) abstracts DOM operations:
this.renderer.setStyle(el, 'color', 'red');
Use Renderer2 for cross-platform rendering, Web Worker support, and security.

Q: What is DomSanitizer used for?
A: DomSanitizer marks untrusted HTML/URLs/styles as safe for Angular to render without stripping:
this.trustedHtml = this.sanitizer.bypassSecurityTrustHtml(value);
Available: bypassSecurityTrustHtml, Script, Style, Url, ResourceUrl. Avoid bypassSecurityTrustHtml on user input — prefer [innerHTML] with sanitization, which is the safe default.

Q: What is the signal input API (input())?
A: Angular 17.1+ adds signal-based inputs:
readonly name = input.required<string>();
readonly age = input(0); // optional with default
Read as functions: {{ name() }}. Inputs are reactive and integrate with computed(). Replace @Input() set name(v: string) with the new API.

Q: What is the model() input/output API?
A: model() creates a two-way bindable signal:
readonly value = model(0);
Use in template: [value]="parentValue" (valueChange)="parentValue = $event" — or use banana syntax with a component that exposes [(value)]="parentValue".
Replaces the need for separate @Input() + @Output() pairs in many cases.

Q: What is the output() API?
A: output() is the signal-era equivalent of @Output():
readonly saved = output<User>();
this.saved.emit(user);
Consumers bind with (saved)="onSaved($event)". Cleaner than EventEmitter and tree-shakable.

Q: What is the input transform API?
A: input() supports a transform function:
readonly size = input(0, { transform: numberAttribute });
readonly disabled = input(false, { transform: booleanAttribute });
numberAttribute and booleanAttribute are built-ins. Useful for accepting attribute-like string values while keeping strongly-typed inputs.

Q: What is input alias in modern Angular?
A: You can alias an input while keeping the class property name:
readonly name = input.required<string>({ alias: 'userName' });
Bind via the alias: <app-greet [userName]="user.name">. This decouples public API names from internal class properties.

Q: What is a query signal (viewChild / contentChild)?
A: Angular 17.2+ adds signal-based query decorators:
readonly header = viewChild<ElementRef>('hdr');
readonly projected = contentChild<MyComponent>(MyComponent);
They return Signals and integrate with effect(). Signal queries are push-based — they emit when the queried element appears, unlike the old @ViewChild static fields.

Q: What is the difference between viewChildren and viewChild?
A: viewChild() returns a Signal<T | undefined> with a single match.
viewChildren() returns a Signal<readonly T[]> with all matches. The children signal re-emits whenever the query results change (e.g., items added or removed). Use viewChildren for dynamic lists of components.

Q: What is the output() with alias?
A: output() supports aliases:
readonly click = output<void>({ alias: 'onClick' });
Bind via the alias: <app-x (onClick)="handle()">. Same pattern as input alias — separates internal vs external API.

Q: What are the limitations of structural directive shorthand?
A: The * shorthand desugars to <ng-template> with bindings. Limitations:
- Only one structural directive per element (without <ng-container>)
- Cannot be applied to multiple elements at once
- No native block syntax — replaced by @if/@for in Angular 17+
Modern Angular prefers @if/@for over the * syntax.

Q: What is the model() input transform pattern?
A: model() accepts an alias option:
readonly value = model(0, { alias: 'count' });
This supports custom two-way binding names while keeping internal property semantics.

Q: What is NgZone?
A: NgZone is Angular's wrapper around Zone.js. It tracks async operations (setTimeout, Promise, events) and triggers change detection. Use NgZone.runOutsideAngular(() => ...) for performance-critical code (e.g., scroll handlers) that should not trigger CD.

Q: What is zoneless change detection?
A: In Angular 18+, apps can run without Zone.js by relying on signals and explicit markForCheck():
bootstrapApplication(App, { providers: [
  provideExperimentalZonelessChangeDetection()
] });
Benefits: smaller bundle, fewer microtasks, faster. Requires signals, OnPush, and explicit reactivity.

Q: What is provideExperimentalZonelessChangeDetection()?
A: This provider configures Angular to skip Zone.js and rely on signals + OnPush for change detection. Required for fully zoneless apps in Angular 18. Scheduled to stabilize as provideZonelessChangeDetection() in a later release.

Q: What is ChangeDetectorRef.markForCheck()?
A: markForCheck() tells Angular to re-check this component (and ancestors) on the next CD cycle. Use with OnPush when a signal-free mutation occurs:
this.data = newValue;
this.cdr.markForCheck();
Signal-based code usually doesn't need this.

Q: What is ChangeDetectorRef.detach() / reattach()?
A: detach() removes a component from the CD tree; reattach() re-adds it. Useful for fully manual control:
this.cdr.detach();
// later
this.cdr.reattach();
this.cdr.detectChanges();
Combined with OnPush this gives precise control but is rarely needed in signal-based apps.

Q: What is ApplicationRef.tick()?
A: ApplicationRef.tick() triggers a full application-wide change detection cycle. Useful in tests and after out-of-band updates:
this.appRef.tick();
Generally avoid in production — prefer OnPush or signals for targeted CD.

Q: What is NgZone.run()?
A: NgZone.run(() => { ... }) executes a callback inside Angular's zone, so any async ops inside trigger change detection. Use to re-enter the zone from runOutsideAngular.

Q: What is provideAnimations() vs provideNoopAnimations()?
A: - provideAnimations() – enables @angular/animations full engine
- provideNoopAnimations() – registers animations but renders synchronously without animation (useful for tests)
- provideAnimationsAsync() – lazy-loads the animation engine on first use
Required once at bootstrap for any @Component({ animations: [...] }) usage.

Q: What is provideHttpClient() vs HttpClientModule?
A: Modern apps use provideHttpClient(withInterceptors([...]), withFetch()). The HttpClientModule is legacy and only needed for module-based apps. provideHttpClient() is recommended for standalone.

Q: What is withFetch() in provideHttpClient?
A: withFetch() switches HttpClient from XHR to the Fetch API. Required for SSR/hydration in Angular 17+ because Fetch is available in server environments. Also enables streaming responses:
provideHttpClient(withFetch())

Q: What is the HttpContext token?
A: HttpContextToken<T> lets you attach metadata to requests that interceptors can read:
export const SKIP_AUTH = new HttpContextToken<boolean>(() => false);
this.http.get('/api/public', { context: new HttpContext().set(SKIP_AUTH, true) });
Cleaner than header-based flags. Built-in token: HttpContextToken.

Q: What are typed responses and the observe option in HttpClient?
A: HttpClient methods accept a generic type and an observe option:
- observe: 'body' (default) – return body
- observe: 'response' – return full HttpResponse with headers/status
- observe: 'events' – return HttpEvent for progress
Example:
this.http.get<User>('/api/user/1', { observe: 'response' })

Q: What is the reportProgress option?
A: Pass { reportProgress: true } to enable upload/download progress events:
this.http.post('/upload', formData, { reportProgress: true, observe: 'events' });
You'll receive HttpEventType.UploadProgress and DownloadProgress events. Only works with XHR; not with withFetch().

Q: What are the types of HttpParams and HttpHeaders?
A: - HttpParams – URL query parameters, immutable; use .set() and .append() returning new instances
- HttpHeaders – HTTP headers, immutable; .set() returns a new instance
Common pitfall: mutating a local variable doesn't affect the request — you must reassign or chain.

Q: What is HttpErrorResponse and how do you handle errors?
A: HttpErrorResponse is thrown for HTTP failures (status outside 200–299). Handle with the second argument to subscribe or with catchError:
this.http.get<User>('/api/u').pipe(catchError(err => of(null))).subscribe(u => ...);
err.status, err.message, and err.error (parsed body) are available.

Q: What is the difference between cold and hot Observables?
A: - Cold Observable: creates a new producer per subscription. Each subscriber gets its own data. HttpClient.get() is cold.
- Hot Observable: producer exists outside the Observable; subscribers share the same stream. fromEvent, Subject are hot.
Use share() / shareReplay() to multicast a cold Observable.

Q: What is shareReplay() used for?
A: shareReplay({ bufferSize: 1, refCount: true }) multicasts an Observable and replays the latest value to new subscribers. Common for caching HTTP results:
this.users$ = this.http.get<User[]>('/api/users').pipe(shareReplay(1));
Avoid memory leaks by setting refCount: true and unsubscribing when no consumers remain.

Q: What is exhaustMap vs switchMap vs mergeMap vs concatMap?
A: - switchMap – cancel previous, subscribe to newest (search)
- mergeMap – run all concurrently (parallel writes)
- concatMap – queue, run in order (writes requiring order)
- exhaustMap – ignore new emissions while one is in flight (submit button)
Pick by ordering and concurrency requirements.

Q: What is takeUntilDestroyed()?
A: takeUntilDestroyed() (from @angular/core/rxjs-interop) automatically completes an Observable when the host directive/component is destroyed:
private route$ = inject(ActivatedRoute).params.pipe(takeUntilDestroyed());
Must be called in an injection context (constructor or explicit DestroyRef).

Q: What is DestroyRef?
A: DestroyRef is an injection token representing a lifecycle owner:
private destroyRef = inject(DestroyRef);
const sub = interval(1000).subscribe(...);
this.destroyRef.onDestroy(() => sub.unsubscribe());
It is the basis for takeUntilDestroyed and custom cleanup hooks.

Q: What is the difference between ngOnInit and the constructor?
A: - The constructor runs when Angular instantiates the class — inputs are not yet set
- ngOnInit runs after the first ngOnChanges — inputs are set, change detection has run once
Use constructor for DI and minimal setup; use ngOnInit for fetching initial data and initialization that depends on inputs.

Q: What is the lifecycle order in Angular?
A: Order for a child component:
1. ngOnChanges (when inputs change)
2. ngOnInit (once)
3. ngDoCheck
4. ngAfterContentInit
5. ngAfterContentChecked
6. ngAfterViewInit
7. ngAfterViewChecked
8. ngOnDestroy
ngAfterContent* hooks fire before ngAfterView* hooks.

Q: What is OnChanges vs DoCheck?
A: ngOnChanges fires only when an @Input reference changes (not mutations). It receives a SimpleChanges map with previous and current values.
ngDoCheck fires on every change detection cycle. Use it for custom dirty checking, but it is expensive — prefer signals or OnPush.

Q: What is AfterViewInit used for?
A: ngAfterViewInit() fires once, after Angular initializes the component's view and child views. Use it to interact with @ViewChild elements (e.g., focus a DOM input). Modifying bound data here requires ChangeDetectorRef.detectChanges() or triggers an ExpressionChangedAfterItHasBeenCheckedError if done synchronously.

Q: What is ExpressionChangedAfterItHasBeenCheckedError?
A: This dev-mode error means that during change detection, a binding's value changed after Angular read it. Common causes:
- Updating @Input()-bound data in ngAfterViewInit
- Updating a parent's bound value during child's CD
Fix with deferred update (setTimeout, Promise.resolve().then()) or ngAfterViewChecked with a flag.

Q: What are signal-based forms?
A: Angular 21+ (experimental) introduces signal-based forms via FormControl.signalValue() / signal inputs. Today, the recommended pattern is to bridge reactive forms with signals:
readonly value = toSignal(this.form.valueChanges);
Or use form.value directly inside computed().

Q: What is FormArray used for?
A: FormArray manages a dynamic list of FormControls or FormGroups:
this.addresses = this.fb.array([this.fb.group({...})]);
this.addresses.push(this.fb.group({...}));
this.addresses.removeAt(i);
Use for repeating form sections whose count changes.

Q: What are cross-field validators in reactive forms?
A: Cross-field validators receive the full AbstractControl (typically a FormGroup) and validate across fields:
const matchValidator: ValidatorFn = (g: AbstractControl) =>
  g.get('password')?.value === g.get('confirm')?.value ? null : { mismatch: true };
this.form = this.fb.group({...}, { validators: [matchValidator] });

Q: What are async validators?
A: Async validators return an Observable/Promise that resolves to validation errors:
const uniqueEmail: AsyncValidatorFn = (c) =>
  this.http.get<boolean>('/api/check?email=' + c.value).pipe(map(taken => taken ? { taken: true } : null));
control.setAsyncValidators(uniqueEmail);
Set on a control, not a group, by default. Use updateValueAndValidity() to re-run.

Q: What is updateOn in FormControl?
A: updateOn changes when the control's value is updated/validated:
- 'change' (default)
- 'blur'
- 'submit'
Example: new FormControl('', { validators: ..., updateOn: 'blur' }).

Q: What is nonNullable FormBuilder in modern Angular?
A: From Angular 14+, FormBuilder.nonNullable produces typed, non-nullable controls:
this.form = this.fb.nonNullable.group({
  name: this.fb.nonNullable.control('Alice'),
  age: 0,
});
Initial values are required; reset() restores them. Strongly recommended for type-safe forms.

Q: What is the difference between valueChanges and statusChanges?
A: - valueChanges emits the new value whenever the form value changes
- statusChanges emits the new status (VALID, INVALID, PENDING, DISABLED) when validation state changes
Use statusChanges to react to validation results without caring about specific values.

Q: What is markAsDirty / markAsTouched / markAsPristine?
A: Control state flags:
- markAsDirty() / markAsPristine() – user-interaction tracking
- markAsTouched() / markAsUntouched() – focus-tracking
Custom UI often calls these to control when error messages appear (e.g., only show after blur).

Q: What are validators: composition in modern Angular?
A: Validators are functions composed in arrays:
email: ['', [Validators.required, Validators.email, Validators.maxLength(120)]]
Errors from all validators are aggregated on control.errors. Use Validators.compose([...]) for shared reusable groups.

Q: What is TestBed in Angular testing?
A: TestBed is the primary Angular testing utility that creates a testing module:
await TestBed.configureTestingModule({
  imports: [MyComponent],
  providers: [{ provide: MyService, useValue: stub }]
}).compileComponents();
const fixture = TestBed.createComponent(MyComponent);

Q: What is ComponentFixture?
A: ComponentFixture is returned by TestBed.createComponent():
- fixture.componentInstance – the component class
- fixture.debugElement – root debug element
- fixture.nativeElement – host DOM element
- fixture.detectChanges() – trigger CD
Use fixture.autoDetectChanges(true) for async zone-aware tests.

Q: What is a ComponentHarness?
A: ComponentHarness (from @angular/cdk/testing) provides a stable, abstracted testing API:
class MyHarness extends ComponentHarness {
  static hostSelector = 'app-my';
  getButton = this.locatorFor('button');
  async click() { await (await this.getButton()).click(); }
}
Tests use harnesses instead of querying DOM directly — they survive markup changes.

Q: What is ng-mocks?
A: ng-mocks is a popular library for testing modules: it lets you MockComponent(MyComponent), MockService(MyService), etc. Useful for isolating a unit under test from its dependencies. Plays well with TestBed.

Q: What is the JIT vs AOT compiler?
A: - JIT (Just-in-Time): compiles templates in the browser. Slower, larger bundles, used in dev mode by default.
- AOT (Ahead-of-Time): compiles templates at build time. Default for production (ng build). Smaller bundles, faster startup, catches template errors earlier.
Angular Universal / SSR also uses AOT.

Q: What is the Ivy renderer?
A: Ivy is Angular's current rendering engine (default since Angular 9). It uses incremental DOM and tree-shakeable code. Benefits: smaller bundles, faster compilation, better debugging, and the foundation for signals and standalone components.

Q: What is Angular Universal (SSR)?
A: Angular Universal renders the application on the server for the initial HTML response, then the browser hydrates it:
bootstrapApplication(AppComponent, {
  providers: [provideClientHydration()]
});
Benefits: faster first paint, SEO, social previews.

Q: What is provideClientHydration()?
A: provideClientHydration() enables hydration: the server-rendered DOM is reused on the client without re-rendering, preserving focus, scroll position, and event listeners. Caveats: must use withFetch(), avoid direct DOM access in lifecycle hooks, and prefer signals/OnPush.

Q: What are incremental hydration and @defer in SSR?
A: Angular 19+ adds incremental hydration — defer server-side rendering of specific template blocks until needed:
@defer (hydrate on viewport) { <heavy-component /> }
Reduces SSR cost and improves TTFB while keeping interactivity.

Q: What are route-level data and resolvers?
A: Route data is static metadata read via ActivatedRoute.data:
{ path: 'about', component: AboutComponent, data: { title: 'About' } }
resolve runs a function (or ResolveFn) to produce dynamic data accessible the same way.

Q: What are typed reactive forms (TypedFormGroup)?
A: Since Angular 14, FormBuilder.group() infers types:
this.form = this.fb.group({
  name: ['', Validators.required],
  age: 0,
});
this.form.controls.name.value // string, not any
Use FormControl<string | null> for nullable cases.

Q: What is the difference between FormControl, FormGroup, and FormRecord?
A: - FormControl – a single input
- FormGroup – a fixed-key collection of controls
- FormRecord – a dynamic-key collection (e.g., user-defined fields)
Prefer FormRecord when keys are not known at compile time.

Q: What is dynamic component creation?
A: Use ViewContainerRef.createComponent() to mount components at runtime:
this.vcr.createComponent(MyComponent);
For dynamic type:
this.vcr.createComponent(await import('./lazy.component').then(m => m.LazyComponent));
Used in dialogs, modals, dashboards.

Q: What is ComponentPortal from CDK?
A: CDK provides ComponentPortal for portal-based rendering:
const portal = new ComponentPortal(MyComponent);
this.cdkPortalOutlet.attach(portal);
Useful for overlays, dialogs, and dynamic UI patterns.

Q: What is the Angular workspace vs project model?
A: An Angular workspace (angular.json) can contain multiple projects: apps and libraries. ng generate library my-lib creates a reusable package within the same workspace. Libraries are built with the ng-packagr tool and published as Angular packages.

Q: What are Angular CLI builders and schematics?
A: - Builders: run tasks like build, test, lint. Configured in angular.json
- Schematics: generate or transform code. ng generate component invokes a schematic
Custom builders/schematics enable repeatable automation in monorepos.

Q: What is ng update?
A: ng update @angular/core @angular/cli ... upgrades dependencies and runs migration schematics that automatically refactor code (e.g., renaming APIs). Always run with --dry-run first to preview changes.

Q: What is ng add?
A: ng add <package> installs a package and runs its add schematic to set up the project. Example: ng add @angular/material installs Material and adds the theme to styles.css.

Q: What is an Angular library and when should I create one?
A: An Angular library is a publishable package within your workspace:
ng generate library ui-kit
Use libraries for shared components, services, and utilities to enforce API boundaries and enable tree-shaking per consumer.

Q: What are standalone exports?
A: A standalone component, directive, or pipe must be exported to be imported elsewhere. If it's already a top-level standalone element (like a route's loadComponent), exporting is implicit. For re-export from a barrel file, list it:
export { MyComponent } from './my.component';

Q: What is the difference between RouterLink and routerLink?
A: routerLink is the directive selector (used in templates):
<a routerLink="/users" routerLinkActive="active">Users</a>
routerLinkActive adds a CSS class when the link is active. routerLink accepts strings, arrays, or UrlTree instances.

Q: What is the difference between router.navigate and router.navigateByUrl?
A: - navigate(commands, extras) – array-based: router.navigate(['users', user.id])
- navigateByUrl(url) – string-based: router.navigateByUrl('/users/1')
Prefer navigate() with arrays because it handles parameter encoding and matrix params cleanly.

Q: What is Location.go() vs router.navigate()?
A: Location.go('/users/1') changes the URL without triggering router navigation. Useful for setting state without re-rendering. router.navigate() goes through the full navigation pipeline (guards, resolvers, components).

Q: What is RouterLinkActive and RouterLinkActiveOptions?
A: routerLinkActive="active" applies the active class when the link's URL matches. Use [routerLinkActiveOptions]="{ exact: true }" to require exact match (otherwise / matches all routes):
<a routerLink="/" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }">Home</a>

Q: What is a global error handler (ErrorHandler)?
A: Implement ErrorHandler to centralize error logging:
@Injectable()
export class GlobalErrorHandler implements ErrorHandler {
  handleError(error: unknown) { Sentry.captureException(error); }
}
{ provide: ErrorHandler, useClass: GlobalErrorHandler }
Catches errors from async code, RxJS, and uncaught exceptions.

Q: What is APP_INITIALIZER and what replaces it?
A: APP_INITIALIZER (legacy) ran functions before app bootstrap to load config. Modern replacement: provideAppInitializer(() => inject(ConfigService).load()) in the providers list. Returns a Promise/Observable. Multi-provider array supported.

Q: What is provideEnvironmentInitializer()?
A: provideEnvironmentInitializer(() => { ... }) runs after providers are configured but before bootstrap. Useful to register side effects (logging, telemetry, registering providers dynamically). Returns nothing.

Q: What is the difference between the global and platform browser providers?
A: - platformBrowser() – registers browser platform services
- Modern: provideBrowserGlobalErrorListeners(), provideBrowserGlobalErrorListeners()
These are usually handled by bootstrapApplication() automatically.

Q: What is the difference between HttpClient.get and HttpClient.request?
A: get(), post(), etc. are conveniences over request<T>(method, url, options). Use request() for custom methods (PATCH, OPTIONS) or when dynamically choosing the verb:
this.http.request<User>('PATCH', '/api/user/1', { body: patch });