Angular coding QA
Angular Coding Exercises
1️⃣ Create a Component Using Angular CLI
ng generate component user
2️⃣ Write a Simple Angular Component
import { Component } from '@angular/core';
@Component({
selector: 'app-test',
template: '<h1>Hello Angular</h1>'
})
export class TestComponent {}
3️⃣ Syntax for ngFor
<li *ngFor="let item of items">{{ item }}</li>
4️⃣ Create a Custom Pipe to Reverse a String
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({ name: 'reverse' })
export class ReversePipe implements PipeTransform {
transform(value: string): string {
return value.split('').reverse().join('');
}
}
// Usage in template
<p>{{ 'Angular' | reverse }}</p> <!-- Output: ralugnA -->
5️⃣ Subscribe to an Observable Using AsyncPipe
<p>{{ data$ | async }}</p>
Explanation: Using AsyncPipe automatically subscribes to an Observable and displays the latest value. It also handles unsubscription when the component is destroyed.
Angular Practical Examples
1️⃣ Create a Service using Angular CLI
ng generate service services/user
2️⃣ Create a Directive using Angular CLI
ng generate directive directives/highlight
3️⃣ Create a Pipe using Angular CLI
ng generate pipe pipes/capitalize
4️⃣ Property Binding Example
<img [src]="imageUrl" /> imageUrl = 'assets/logo.png';
5️⃣ Event Binding Example
<button (click)="sayHello()">Click</button>
sayHello() {
alert("Hello Angular!");
}
6️⃣ Two-way Binding Example
<input [(ngModel)]="name" />
<p>{{ name }}</p>
name = '';
7️⃣ Custom Directive: Highlight on Hover
import { Directive, ElementRef, HostListener, Renderer2 } from '@angular/core';
@Directive({
selector: '[appHighlight]'
})
export class HighlightDirective {
constructor(private el: ElementRef, private renderer: Renderer2) {}
@HostListener('mouseenter') onMouseEnter() {
this.renderer.setStyle(this.el.nativeElement, 'backgroundColor', 'yellow');
}
@HostListener('mouseleave') onMouseLeave() {
this.renderer.removeStyle(this.el.nativeElement, 'backgroundColor');
}
}
Usage:
<p appHighlight>Hover me</p>
8️⃣ Custom Pipe: Capitalize First Letter
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({ name: 'capitalize' })
export class CapitalizePipe implements PipeTransform {
transform(value: string): string {
if (!value) return '';
return value.charAt(0).toUpperCase() + value.slice(1);
}
}
Usage:
<p>{{ 'angular' | capitalize }}</p>
9️⃣ Create an Interface and Use it in an Array
export interface User {
id: number;
name: string;
email: string;
}
users: User[] = [
{ id: 1, name: 'Sai', email: 'sai@gmail.com' },
{ id: 2, name: 'Balaji', email: 'balaji@gmail.com' }
];
🔟 Use ngIf with else
<div *ngIf="isLoggedIn; else loginBlock"> Welcome User! </div> <ng-template #loginBlock> Please login </ng-template>
1️⃣1️⃣ Create a Reactive Form (Basic)
// component.ts
import { FormControl, FormGroup, Validators } from '@angular/forms';
form = new FormGroup({
name: new FormControl('', Validators.required),
email: new FormControl('', [Validators.required, Validators.email])
});
submit() {
console.log(this.form.value);
}
// component.html
<form [formGroup]="form" (ngSubmit)="submit()">
<input formControlName="name" placeholder="Name" />
<input formControlName="email" placeholder="Email" />
<button type="submit">Submit</button>
</form>
1️⃣2️⃣ Call API using HttpClient (GET)
// service.ts
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class UserService {
constructor(private http: HttpClient) {}
getUsers(): Observable<any[]> {
return this.http.get<any[]>('https://jsonplaceholder.typicode.com/users');
}
}
// component.ts
users: any[] = [];
constructor(private userService: UserService) {}
ngOnInit() {
this.userService.getUsers().subscribe(res => {
this.users = res;
});
}
1️⃣3️⃣ Async Pipe with HttpClient
users$ = this.userService.getUsers();
<li *ngFor="let user of users$ | async">
{{ user.name }}
</li>
1️⃣4️⃣ Create a Route (Routing Module)
const routes: Routes = [
{ path: 'home', component: HomeComponent },
{ path: 'users', component: UsersComponent }
];
1️⃣5️⃣ Navigation using RouterLink
<a routerLink="/users">Users</a>
1️⃣6️⃣ Route Parameter Example
// route
{ path: 'user/:id', component: UserDetailsComponent }
// reading param
constructor(private route: ActivatedRoute) {}
ngOnInit() {
const id = this.route.snapshot.paramMap.get('id');
console.log(id);
}
✅ Advanced Angular Coding Exercises (Angular 17+)
1️⃣ Create a Standalone Component
ng generate component dashboard --standalone
import { Component } from '@angular/core';
@Component({
selector: 'app-dashboard',
standalone: true,
template: `<h2>Dashboard Works!</h2>`
})
export class DashboardComponent {}
2️⃣ Create a Route Guard (AuthGuard)
ng generate guard guards/auth
import { CanActivateFn, Router } from '@angular/router';
import { inject } from '@angular/core';
export const authGuard: CanActivateFn = () => {
const router = inject(Router);
const token = localStorage.getItem('token');
if (!token) {
router.navigate(['/login']);
return false;
}
return true;
};
Usage:
{ path: 'dashboard', component: DashboardComponent, canActivate: [authGuard] }
3️⃣ Create an HTTP Interceptor (JWT Token)
ng generate interceptor interceptors/auth
import { HttpInterceptorFn } from '@angular/common/http';
export const authInterceptor: HttpInterceptorFn = (req, next) => {
const token = localStorage.getItem('token');
if (token) {
req = req.clone({
setHeaders: { Authorization: `Bearer ${token}` }
});
}
return next(req);
};
Register in app.config.ts:
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { authInterceptor } from './interceptors/auth.interceptor';
export const appConfig = {
providers: [provideHttpClient(withInterceptors([authInterceptor]))]
};
4️⃣ Handle HTTP Error using catchError
import { catchError, throwError } from 'rxjs';
getUsers() {
return this.http.get<any[]>('/api/users').pipe(
catchError(err => {
console.error("API Error:", err);
return throwError(() => err);
})
);
}
5️⃣ BehaviorSubject Login State (AuthService)
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class AuthService {
private isLoggedInSubject = new BehaviorSubject<boolean>(false);
isLoggedIn$ = this.isLoggedInSubject.asObservable();
login(token: string) {
localStorage.setItem('token', token);
this.isLoggedInSubject.next(true);
}
logout() {
localStorage.removeItem('token');
this.isLoggedInSubject.next(false);
}
}
6️⃣ Debounce Search using RxJS
import { FormControl } from '@angular/forms';
import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs';
import { UserService } from './user.service';
searchControl = new FormControl('');
users$ = this.searchControl.valueChanges.pipe(
debounceTime(500),
distinctUntilChanged(),
switchMap(value => this.userService.searchUsers(value || ''))
);
constructor(private userService: UserService) {}
HTML:
<input [formControl]="searchControl" placeholder="Search users..." />
<ul>
<li *ngFor="let user of users$ | async">{{ user.name }}</li>
</ul>
7️⃣ Lazy Loading Module
ng generate module admin --route admin --module app.module
{
path: 'admin',
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
}
8️⃣ Route Resolver (Load Data Before Page Loads)
import { ResolveFn } from '@angular/router';
import { inject } from '@angular/core';
import { UserService } from './user.service';
export const userResolver: ResolveFn<any> = (route) => {
const userService = inject(UserService);
const id = route.paramMap.get('id')!;
return userService.getUserById(id);
};
Route usage:
{ path: 'user/:id', component: UserDetailsComponent, resolve: { user: userResolver } }
Component:
constructor(private route: ActivatedRoute) {}
ngOnInit() {
const user = this.route.snapshot.data['user'];
console.log(user);
}
9️⃣ TrackBy with ngFor (Performance Optimization)
<li *ngFor="let user of users; trackBy: trackById">{{ user.name }}</li>
trackById(index: number, user: any) {
return user.id;
}
1️⃣0️⃣ ChangeDetectionStrategy.OnPush
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
@Component({
selector: 'app-user-card',
template: `<p>{{ user.name }}</p>`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserCardComponent {
@Input() user: any;
}
1️⃣1️⃣ Signals (Angular 17+)
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-counter',
template: `
<h2>{{ count() }}</h2>
<button (click)="increment()">+</button>
`
})
export class CounterComponent {
count = signal(0);
increment() {
this.count.update(v => v + 1);
}
}
1️⃣2️⃣ Signal + Computed Example
import { Component, signal, computed } from '@angular/core';
@Component({
selector: 'app-total',
template: `
<p>Price: {{ price() }}</p>
<p>Qty: {{ qty() }}</p>
<p>Total: {{ total() }}</p>
`
})
export class TotalComponent {
price = signal(100);
qty = signal(2);
total = computed(() => this.price() * this.qty());
}
1️⃣3️⃣ Dynamic FormArray
import { FormArray, FormBuilder, Validators } from '@angular/forms';
constructor(private fb: FormBuilder) {}
form = this.fb.group({
items: this.fb.array([])
});
get items() {
return this.form.get('items') as FormArray;
}
addItem() {
this.items.push(
this.fb.group({
name: ['', Validators.required],
qty: [1, Validators.required]
})
);
}
HTML:
<div formArrayName="items">
<div *ngFor="let item of items.controls; let i=index" [formGroupName]="i">
<input formControlName="name" placeholder="Item Name" />
<input formControlName="qty" type="number" />
</div>
</div>
<button (click)="addItem()">Add Item</button>
1️⃣4️⃣ Custom Validator (Password Match)
import { AbstractControl, ValidationErrors } from '@angular/forms';
export function passwordMatchValidator(control: AbstractControl): ValidationErrors | null {
const password = control.get('password')?.value;
const confirm = control.get('confirmPassword')?.value;
if (password !== confirm) {
return { passwordMismatch: true };
}
return null;
}
form = new FormGroup(
{
password: new FormControl(''),
confirmPassword: new FormControl('')
},
{ validators: passwordMatchValidator }
);
✅ SUPER ADVANCED Angular Coding Exercises (ALL)
1) NgRx Store (Mini Example: Actions → Reducer → Selector)
Install:
ng add @ngrx/store
counter.actions.ts
import { createAction } from '@ngrx/store';
export const increment = createAction('[Counter] Increment');
export const decrement = createAction('[Counter] Decrement');
export const reset = createAction('[Counter] Reset');
counter.reducer.ts
import { createReducer, on } from '@ngrx/store';
import { increment, decrement, reset } from './counter.actions';
export const initialState = 0;
export const counterReducer = createReducer(
initialState,
on(increment, state => state + 1),
on(decrement, state => state - 1),
on(reset, () => 0)
);
app.module.ts
import { StoreModule } from '@ngrx/store';
import { counterReducer } from './store/counter.reducer';
@NgModule({
imports: [
StoreModule.forRoot({ count: counterReducer })
]
})
export class AppModule {}
counter.component.ts
import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { increment, decrement, reset } from './store/counter.actions';
@Component({
selector: 'app-counter',
template: `
{{ count$ | async }}
`
})
export class CounterComponent {
count$ = this.store.select(state => state.count);
constructor(private store: Store<{ count: number }>) {}
inc() { this.store.dispatch(increment()); }
dec() { this.store.dispatch(decrement()); }
res() { this.store.dispatch(reset()); }
}
2) SSR (Angular Universal) Setup
ng add @nguniversal/express-engine
• SEO friendly
• Faster first load
• Better performance for public websites
3) PWA Setup
ng add @angular/pwa
• Service worker
• Offline caching
• Installable web app
4) Unit Testing (Jasmine + Karma) Component Test
component.ts
@Component({
selector: 'app-test',
template: `{{ title }}
`
})
export class TestComponent {
title = 'Angular Testing';
}
component.spec.ts
import { TestBed } from '@angular/core/testing';
import { TestComponent } from './test.component';
describe('TestComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TestComponent]
});
});
it('should create component', () => {
const fixture = TestBed.createComponent(TestComponent);
const comp = fixture.componentInstance;
expect(comp).toBeTruthy();
});
it('should have correct title', () => {
const fixture = TestBed.createComponent(TestComponent);
expect(fixture.componentInstance.title).toBe('Angular Testing');
});
});
5) WebSocket Real-time Example (Observable)
web-socket.service.ts
import { Injectable } from '@angular/core';
import { webSocket } from 'rxjs/webSocket';
@Injectable({ providedIn: 'root' })
export class WebSocketService {
private socket$ = webSocket('ws://localhost:8080');
sendMessage(msg: string) {
this.socket$.next(msg);
}
getMessages() {
return this.socket$;
}
}
component.ts
messages: string[] = [];
ngOnInit() {
this.ws.getMessages().subscribe(msg => {
this.messages.push(msg as string);
});
}
6) ViewChild Example (Access Child Component)
child.component.ts
@Component({
selector: 'app-child',
template: `Child Component
`
})
export class ChildComponent {
sayHello() {
return "Hello from child!";
}
}
parent.component.ts
import { ViewChild } from '@angular/core';
import { ChildComponent } from './child.component';
@ViewChild(ChildComponent) child!: ChildComponent;
ngAfterViewInit() {
console.log(this.child.sayHello());
}
7) Dynamic Component Loading (Advanced)
import { ViewContainerRef } from '@angular/core';
constructor(private vcr: ViewContainerRef) {}
loadComponent() {
import('./card/card.component').then(({ CardComponent }) => {
this.vcr.createComponent(CardComponent);
});
}
8) Global Error Handler (Production)
import { ErrorHandler, Injectable } from '@angular/core';
@Injectable()
export class GlobalErrorHandler implements ErrorHandler {
handleError(error: any) {
console.error("Global Error:", error);
// send error to server/log system
}
}
Register:
providers: [{ provide: ErrorHandler, useClass: GlobalErrorHandler }]
9) If and Nested If Conditions (TypeScript)
Simple if
let age = 20;
if (age >= 18) {
console.log("Adult");
}
If else
if (age >= 18) {
console.log("Adult");
} else {
console.log("Minor");
}
Nested if
let marks = 85;
if (marks >= 35) {
if (marks >= 90) {
console.log("Grade A+");
} else if (marks >= 75) {
console.log("Grade A");
} else {
console.log("Grade B");
}
} else {
console.log("Fail");
}
10) If and Nested If Conditions in Angular HTML
Using *ngIf with else
<div *ngIf="isLoggedIn; else loginBlock">
Welcome User!
</div>
<ng-template #loginBlock>
Please login
</ng-template>
Nested *ngIf
<div *ngIf="isLoggedIn">
<div *ngIf="isAdmin; else userBlock">
Welcome Admin
</div>
<ng-template #userBlock>
Welcome Normal User
</ng-template>
</div>
11) Advanced RxJS: switchMap vs mergeMap (Interview)
this.searchControl.valueChanges.pipe(
debounceTime(500),
distinctUntilChanged(),
switchMap(value => this.api.search(value))
);
12) Angular Signal + API (Modern Angular)
import { signal } from '@angular/core';
users = signal<any[]>([]);
loadUsers() {
this.http.get<any[]>('/api/users').subscribe(res => {
this.users.set(res);
});
}
HTML:
<li *ngFor="let u of users()">{{ u.name }}</li>
13) JWT Role-Based Guard (Admin Only)
export const adminGuard: CanActivateFn = () => {
const router = inject(Router);
const role = localStorage.getItem("role");
if (role !== "Admin") {
router.navigate(['/unauthorized']);
return false;
}
return true;
};
14) HTTP Retry + Error Handling
import { retry, catchError, throwError } from 'rxjs';
getData() {
return this.http.get('/api/data').pipe(
retry(2),
catchError(err => throwError(() => err))
);
}
✅ ULTRA PRO ANGULAR CODING EXERCISES (ALL)
1) Create a Custom Structural Directive (*appIf)
app-if.directive.ts
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[appIf]'
})
export class AppIfDirective {
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef
) {}
@Input() set appIf(condition: boolean) {
this.viewContainer.clear();
if (condition) {
this.viewContainer.createEmbeddedView(this.templateRef);
}
}
}
Usage:
<h2 *appIf="isLoggedIn">Welcome User</h2>
2) Custom Preloading Strategy (Lazy Loading Optimization)
custom-preload.strategy.ts
import { Injectable } from '@angular/core';
import { PreloadingStrategy, Route } from '@angular/router';
import { Observable, of } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class CustomPreloadStrategy implements PreloadingStrategy {
preload(route: Route, load: () => Observable<any>): Observable<any> {
return route.data?.['preload'] ? load() : of(null);
}
}
app-routing.module.ts
RouterModule.forRoot(routes, {
preloadingStrategy: CustomPreloadStrategy
})
Route Example:
{
path: 'admin',
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule),
data: { preload: true }
}
3) Route Reuse Strategy (Cache Components Like Tabs)
custom-reuse.strategy.ts
import { RouteReuseStrategy, DetachedRouteHandle, ActivatedRouteSnapshot } from '@angular/router';
export class CustomReuseStrategy implements RouteReuseStrategy {
private storedRoutes = new Map<string, DetachedRouteHandle>();
shouldDetach(route: ActivatedRouteSnapshot): boolean {
return route.routeConfig?.path === 'dashboard';
}
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
this.storedRoutes.set(route.routeConfig!.path!, handle);
}
shouldAttach(route: ActivatedRouteSnapshot): boolean {
return this.storedRoutes.has(route.routeConfig!.path!);
}
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null {
return this.storedRoutes.get(route.routeConfig!.path!) || null;
}
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
}
}
Register:
providers: [{ provide: RouteReuseStrategy, useClass: CustomReuseStrategy }]
4) Angular CDK Virtual Scroll (For Huge Lists)
Install:
ng add @angular/cdk
HTML Example:
<cdk-virtual-scroll-viewport itemSize="50" style="height: 300px">
<div *cdkVirtualFor="let user of users">
{{ user.name }}
</div>
</cdk-virtual-scroll-viewport>
5) Lazy Load Standalone Component (Angular 17+)
routes.ts
export const routes = [
{
path: 'profile',
loadComponent: () =>
import('./profile/profile.component').then(m => m.ProfileComponent)
}
];
6) Micro Frontend Angular (Module Federation)
Install:
ng add @angular-architects/module-federation
Run Commands:
ng g @angular-architects/module-federation:init --project shell --type host
ng g @angular-architects/module-federation:init --project mfe1 --type remote
• Big enterprise apps
• Multiple teams working separately
• Deploy parts independently
7) NX Workspace (Monorepo) Setup
npx create-nx-workspace@latest
• Multiple Angular apps
• Shared libs
• Better CI/CD
• Faster builds
8) Bundle Analyzer (Find Heavy Libraries)
Build Stats:
ng build --stats-json
Analyze:
npx webpack-bundle-analyzer dist/yourapp/stats.json
9) Advanced RxJS: Combine Multiple APIs with forkJoin
import { forkJoin } from 'rxjs';
loadDashboard() {
forkJoin({
users: this.http.get('/api/users'),
invoices: this.http.get('/api/invoices'),
projects: this.http.get('/api/projects')
}).subscribe(result => {
console.log(result.users, result.invoices, result.projects);
});
}
10) Advanced RxJS: Caching API Calls using shareReplay
import { shareReplay } from 'rxjs/operators';
users$ = this.http.get('/api/users').pipe(
shareReplay(1)
);
11) HTTP Interceptor: Add JWT + Refresh Token (Pro)
auth.interceptor.ts
import { Injectable } from '@angular/core';
import {
HttpInterceptor,
HttpRequest,
HttpHandler,
HttpEvent
} from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const token = localStorage.getItem("token");
if (token) {
req = req.clone({
setHeaders: { Authorization: `Bearer ${token}` }
});
}
return next.handle(req);
}
}
Register:
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
]
12) Resolver: Load Data Before Route Opens
users.resolver.ts
import { ResolveFn } from '@angular/router';
import { inject } from '@angular/core';
export const usersResolver: ResolveFn<any> = () => {
const http = inject(HttpClient);
return http.get('/api/users');
};
routes.ts
{
path: 'users',
component: UsersComponent,
resolve: { users: usersResolver }
}
component.ts
constructor(private route: ActivatedRoute) {}
ngOnInit() {
console.log(this.route.snapshot.data['users']);
}
13) Advanced Form Validation (Async Validator)
username.validator.ts
import { AbstractControl } from '@angular/forms';
import { map } from 'rxjs/operators';
import { inject } from '@angular/core';
export function usernameAsyncValidator() {
const http = inject(HttpClient);
return (control: AbstractControl) => {
return http.get<any>(`/api/users/check/${control.value}`).pipe(
map(res => (res.exists ? { usernameTaken: true } : null))
);
};
}
Usage:
this.form = this.fb.group({
username: ['', null, [usernameAsyncValidator()]]
});
14) Dynamic Reactive Form (Add/Remove Controls)
component.ts
skills = this.fb.array([]);
form = this.fb.group({
name: [''],
skills: this.skills
});
addSkill() {
this.skills.push(this.fb.control(''));
}
removeSkill(i: number) {
this.skills.removeAt(i);
}
HTML:
<div formArrayName="skills">
<div *ngFor="let s of skills.controls; let i=index">
<input [formControlName]="i">
<button (click)="removeSkill(i)">Remove</button>
</div>
</div>
<button (click)="addSkill()">Add Skill</button>
15) Signal + Computed + Effect (Angular Modern)
import { signal, computed, effect } from '@angular/core';
count = signal(0);
doubleCount = computed(() => this.count() * 2);
constructor() {
effect(() => {
console.log("Count changed:", this.count());
});
}
increment() {
this.count.update(v => v + 1);
}
16) Pro-Level Nested If Conditions (Angular + TS)
TypeScript Nested If (Permissions Example):
if (this.isLoggedIn) {
if (this.role === 'Admin') {
console.log("Show Admin Dashboard");
} else if (this.role === 'Manager') {
console.log("Show Manager Dashboard");
} else {
console.log("Show User Dashboard");
}
} else {
console.log("Redirect to Login");
}
HTML Nested If (Permissions Example):
<div *ngIf="isLoggedIn; else loginBlock">
<div *ngIf="role === 'Admin'; else notAdmin">
<h2>Admin Dashboard</h2>
</div>
<ng-template #notAdmin>
<div *ngIf="role === 'Manager'; else normalUser">
<h2>Manager Dashboard</h2>
</div>
<ng-template #normalUser>
<h2>User Dashboard</h2>
</ng-template>
</ng-template>
</div>
<ng-template #loginBlock>
<h2>Please Login</h2>
</ng-template>
Comments
Post a Comment