Angular
Angular
Hierarchical DI: Angular allows different injectors at different levels in the component
tree.
ts
@Injectable({
providedIn: 'root' // Available throughout the application
1/330
})
export class MyService {
constructor() { }
}
ts
@NgModule({
providers: [MyService]
})
export class AppModule { }
ts
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
providers: [MyService] // New instance created for this component and its
children
})
export class ExampleComponent {
constructor(private myService: MyService) { }
}
ts
ts
2/330
constructor(@Optional() private myService?: MyService) { }
ts
@NgModule({
providers: [{ provide: API_URL, useValue: 'https://api.example.com' }]
})
export class AppModule { }
1. Tree-Shakable Providers
ts
@Component({
selector: 'app-standalone',
standalone: true,
template: '<h1>Standalone Component</h1>',
providers: [MyService]
})
export class StandaloneComponent {
3/330
constructor(private myService: MyService) { }
}
ts
ts
ts
4/330
4. Differences Between Angular 14 and Angular 19 in DI
Feature Angular 14 Angular 19
5. Summary
Angular 14 follows the traditional DI approach using providedIn: 'root' , module-
level, and component-level DI.
5/330
1. Components in Angular
What is a Component?
A component is the building block of an Angular application. It controls a section of the UI
and consists of:
Component Structure
A component in Angular is created using the @Component decorator.
ts
@Component({
selector: 'app-hello',
template: `<h1>{{ message }}</h1>`,
styles: [`h1 { color: blue; }`]
})
export class HelloComponent {
message: string = 'Hello, Angular!';
}
html
6/330
<app-hello></app-hello>
2. Directives in Angular
Directives are special markers in Angular that change the behavior or appearance of
elements. There are three types:
*ngIf
*ngFor
*ngSwitch
html
ts
isVisible = true;
html
<ul>
<li *ngFor="let item of items">{{ item }}</li>
</ul>
ts
7/330
items = ['Angular', 'React', 'Vue'];
html
ts
isHighlighted = false;
css
ts
@Directive({
selector: '[appHighlight]'
8/330
})
export class HighlightDirective {
constructor(private el: ElementRef, private renderer: Renderer2) {}
@HostListener('mouseenter') onMouseEnter() {
this.renderer.setStyle(this.el.nativeElement, 'background-color', 'yellow');
}
@HostListener('mouseleave') onMouseLeave() {
this.renderer.setStyle(this.el.nativeElement, 'background-color',
'transparent');
}
}
Usage:
html
3. Pipes in Angular
Pipes transform data before displaying it in the view. Built-in pipes include:
html
9/330
<p>Uppercase: {{ 'angular' | uppercase }}</p> <!-- Output: ANGULAR -->
<p>Date: {{ today | date:'fullDate' }}</p> <!-- Output: Friday, March 15, 2025 -
->
<p>Currency: {{ price | currency:'USD' }}</p> <!-- Output: $100.00 -->
ts
ts
@Pipe({
name: 'reverseText'
})
export class ReverseTextPipe implements PipeTransform {
transform(value: string): string {
return value.split('').reverse().join('');
}
}
Usage in Template:
html
10/330
4. Data Binding in Angular
Data binding connects the TypeScript code with the HTML template. There are four types:
4.1 Interpolation ( {{ }} )
One-way binding from TypeScript to the template.
html
ts
html
<img [src]="imageUrl">
ts
imageUrl = 'https://angular.io/assets/images/logos/angular/angular.svg';
html
11/330
ts
message = '';
showMessage() {
this.message = 'Button Clicked!';
}
html
<input [(ngModel)]="name">
<p>Hello, {{ name }}!</p>
ts
name = 'Angular';
12/330
Final Thoughts
Components manage the UI and logic.
13/330
console.log(message); // Output: Hello, World!
3. String Interpolation
String interpolation allows embedding variables and expressions inside template literals.
The ${} syntax allows embedding variables directly inside the string.
let x = 10;
let y = 20;
console.log(`The sum of x and y is ${x + y}.`);
// Output: The sum of x and y is 30.
4. Multiline Strings
Template literals support multiline strings without using \n .
14/330
Example: Without Template Literals (Using \n )
js
5. Tagged Templates
A tagged template is a feature that allows calling a function to process the template literals
before returning the final output.
js
15/330
function tagExample(strings, name, age) {
return `${strings[0]}${name.toUpperCase()}${strings[1]}${age * 2}${strings[2]}`;
}
How it works?
strings → An array of static parts ( ["Hello, ", ". You are ", " years old."] )
name → "Bob"
age → 20
let person = {
name: "Charlie",
address: {
city: "New York",
zip: 10001
}
};
16/330
console.log(info);
// Output: Name: Charlie, City: New York, ZIP: 10001
function getDiscount() {
return 10;
}
js
let html = `
17/330
<div>
<h2>${title}</h2>
<p>${content}</p>
</div>
`;
document.body.innerHTML = html;
The ${} syntax allows dynamically inserting variables into the HTML.
js
18/330
10. Summary
✔ Template Literals use **backticks ( )** instead of quotes. ✔ **Expression
Interpolation** allows inserting values using ** ${} **. ✔ Supports **multiline
Would you like a real-world example using template literals in an Angular project? 😊🚀
*ngIf is not being used now..explain its replacement along
with other changes made?
You're right! In recent versions of Angular (Angular 17+ and Angular 18, 19), the framework
introduced control flow syntax, which replaces structural directives like *ngIf , *ngFor , and
*ngSwitch with a more optimized block template syntax.
html
@if (isLoggedIn) {
<p>Welcome back!</p>
}
19/330
Handling else condition
html
<ng-template #notLoggedIn>
<p>Please log in.</p>
</ng-template>
html
@if (isLoggedIn) {
<p>Welcome back!</p>
} @else {
<p>Please log in.</p>
}
<ul>
<li *ngFor="let item of items">{{ item }}</li>
</ul>
20/330
<ul>
@for (item of items; track item) {
<li>{{ item }}</li>
}
</ul>
<div [ngSwitch]="status">
<p *ngSwitchCase="'active'">User is active</p>
<p *ngSwitchCase="'inactive'">User is inactive</p>
<p *ngSwitchDefault>User status unknown</p>
</div>
@switch (status) {
@case ('active') {
<p>User is active</p>
}
@case ('inactive') {
<p>User is inactive</p>
}
@default {
<p>User status unknown</p>
}
}
21/330
✔ More concise and closer to JavaScript switch-case.
✔ Better syntax highlighting in modern editors.
✔ No extra div needed to wrap ngSwitch .
html
ts
22/330
count = signal(0);
increment() {
this.count.set(this.count() + 1);
}
}
html
*ngFor <li *ngFor="let item of items"> @for (item of items; track item) {
<li> </li> }
23/330
Final Thoughts
If you are migrating from Angular 16 to 17+, you can gradually adopt the new syntax.
The old syntax ( *ngIf , *ngFor , etc.) still works, but the new block template syntax is
recommended.
Would you like help with upgrading your Angular project to use the latest syntax? 🚀😊
Explain deferrable Views and its uses in detail.
html
24/330
<p>Loading...</p>
}
✅ How it works?
@defer (when isDataLoaded) → The content inside {} is rendered only when
html
html
25/330
<p>Here is the deferred content!</p>
}
The content is rendered only when the button is clicked ( showContent = true ).
html
prefetch → Fetches the data before rendering, reducing waiting time when it’s finally
needed.
html
26/330
Defers rendering until the element appears in the viewport (scroll into view).
html
html
The app-heavy-component loads only when the user scrolls to it, improving
performance.
27/330
@defer (when loadData) {
<p>Data is now available!</p>
} @placeholder {
<p>Loading data...</p>
} @loading {
<p>Please wait, fetching data...</p>
} @error {
<p>Oops! Something went wrong.</p>
}
✅ Breakdown:
@placeholder → Displays a temporary UI while waiting for data.
html
html
28/330
Defer API-dependent content until data is available.
html
html
Initial Rendering Still part of the DOM Not loaded until triggered
Performance Can impact load time Reduces bundle size and improves speed
29/330
✔ Better UX → Provides @placeholder , @loading , and @error handling.
✔ Improves Readability → Cleaner, declarative syntax for lazy loading.
9. Final Thoughts
@defer is one of the biggest performance improvements in Angular 17+.
Works well with lazy loading, background fetching, and viewport-based rendering.
✅ Created by Microsoft
✅ Superset of JavaScript → All JavaScript code is valid TypeScript
✅ Compiles to JavaScript → Runs on browsers, Node.js, and anywhere JS runs
✅ Enhances productivity with static typing, interfaces, and modern ECMAScript features
Installing TypeScript
You can install TypeScript globally using npm:
sh
30/330
sh
tsc --version
ts
2️⃣ Interfaces
Interfaces define a structure for objects, ensuring consistency.
ts
interface Person {
name: string;
age: number;
}
31/330
age: 25
};
ts
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
makeSound(): void {
console.log("Some sound...");
}
}
32/330
4️⃣ Enums
Enums allow defining a set of named constants.
ts
enum Status {
Pending,
Approved,
Rejected
}
5️⃣ Generics
Generics allow defining reusable components that work with multiple data types.
ts
console.log(identity<number>(10)); // 10
console.log(identity<string>("Hello")); // Hello
ts
ts
ts
interface Employee {
name: string;
department: string;
}
interface Manager {
level: string;
}
34/330
const lead: TeamLead = {
name: "Alice",
department: "IT",
level: "Senior"
};
8️⃣ Tuples
Tuples allow defining fixed-length arrays with specific types.
ts
ts
35/330
✔ Optional parameters ( ? ) make function calls flexible.
✔ Default values avoid undefined values.
ts
class Car {
readonly brand: string;
private speed: number;
getSpeed(): number {
return this.speed;
}
}
3. TypeScript vs JavaScript
36/330
Feature JavaScript TypeScript
sh
tsc myfile.ts
5. Conclusion
✅ TypeScript enhances JavaScript with static types, interfaces, and OOP.
✅ Improves performance and code quality by catching errors early.
✅ Used by major frameworks like Angular, React (with TypeScript), and NestJS.
Would you like help setting up TypeScript in an Angular project? 🚀😊
🚀
Advanced TypeScript Features
Explained
37/330
1. Advanced Types in TypeScript
TypeScript provides several advanced types to handle complex data structures efficiently.
ts
type Employee = {
name: string;
age: number;
department: string;
};
✅ Benefits:
Improves code readability.
Allows reusability.
ts
38/330
type ID = string | number;
let userId: ID;
ts
✅ Benefits:
Union makes variables flexible.
ts
type User = {
name: string;
age: number;
};
39/330
type ReadonlyUser = {
readonly [K in keyof User]: User[K];
};
2. Optional Chaining ( ?. )
Optional chaining prevents runtime errors when accessing nested properties that might be
null or undefined .
ts
const user = {
name: "Alice",
address: {
city: "New York"
}
};
3. Nullish Coalescing ( ?? )
40/330
Nullish coalescing ( ?? ) provides a default value only if the left-hand operand is null or
undefined.
ts
ts
class Car {
readonly brand: string;
constructor(brand: string) {
this.brand = brand;
}
}
41/330
✅ Ensures data consistency
✅ Prevents accidental modifications
ts
type DeepReadonly<T> = {
readonly [K in keyof T]: DeepReadonly<T[K]>;
};
type Config = {
appName: string;
settings: {
theme: string;
};
};
Conclusion
42/330
✅ Advanced Types like Union, Intersection, Type Aliases improve code flexibility.
✅ Optional Chaining ( ) prevents errors when accessing nested properties.
?.
✅ Nullish Coalescing ( ) provides safe fallback values.
??
✅ Readonly & Immutability protect objects from accidental changes.
Would you like an example combining all these features in a real-world scenario? 🚀😊
Explain reactive programming with Rxjs -different types of
observables.difference between subject and observables
🚀
etc.
2. What is RxJS?
RxJS (Reactive Extensions for JavaScript) is a powerful library for handling reactive
programming in JavaScript and TypeScript.
Concept Description
43/330
Concept Description
ts
44/330
Example: Hot Observable
ts
setTimeout(() => {
hotObservable.subscribe(value => console.log('Subscriber 2:', value));
}, 3000);
4. Subjects in RxJS
A Subject is a special type of observable that allows multicasting (multiple subscribers
receive the same values).
Types of Subjects
Subject Type Behavior
BehaviorSubject Stores the last emitted value and emits it to new subscribers.
ReplaySubject Stores a buffer of previous values and replays them to new subscribers.
45/330
Useful for event-based communication.
Example: Subject
ts
subject.next(1);
subject.next(2);
subject.next(3);
✅ Subscriber 2 does not receive 1 and 2 because Subjects do not store values.
2️⃣ BehaviorSubject
Stores the last emitted value.
Example: BehaviorSubject
ts
behaviorSubject.next(1);
behaviorSubject.next(2);
46/330
behaviorSubject.subscribe(value => console.log('Subscriber 2:', value)); // Gets
last value (2)
behaviorSubject.next(3);
3️⃣ ReplaySubject
Stores a history of values and replays them to new subscribers.
Example: ReplaySubject
ts
replaySubject.next(1);
replaySubject.next(2);
replaySubject.next(3);
4️⃣ AsyncSubject
Emits only the last value after completion.
Example: AsyncSubject
ts
47/330
import { AsyncSubject } from 'rxjs';
asyncSubject.next(1);
asyncSubject.next(2);
asyncSubject.next(3);
Execution New execution for each Shared execution for all subscribers
subscriber
6. Operators in RxJS
RxJS provides operators to transform and control data streams.
Operator Purpose
48/330
Operator Purpose
ts
of(1, 2, 3, 4, 5)
.pipe(
filter(num => num % 2 === 0), // Only even numbers
map(num => num * 10) // Multiply each by 10
)
.subscribe(value => console.log(value)); // 20, 40
7. Conclusion
✔ Reactive Programming is a powerful paradigm for handling asynchronous events.
✔ RxJS Observables enable reactive data streams.
✔ Subjects allow multicasting and state management.
✔ RxJS Operators simplify data transformations.
🚀
RxJS Operators: A Detailed Guide with
Examples
49/330
RxJS operators are functions that allow us to transform, filter, combine, and control data
streams in Observables.
1. Creation Operators
✅ Used to create new Observables.
Operator Description
50/330
✅ interval() never completes, so you must unsubscribe manually.
2. Transformation Operators
✅ Modify values emitted by an Observable.
Operator Description
of(2, 4, 6)
.pipe(map(num => num * 10))
.subscribe(value => console.log(value)); // 20, 40, 60
click$.pipe(
51/330
switchMap(() => interval(1000).pipe(take(3))) // Cancels previous interval
).subscribe(value => console.log('SwitchMap:', value));
click$.pipe(
mergeMap(() => interval(1000).pipe(take(3))) // Runs all intervals in parallel
).subscribe(value => console.log('MergeMap:', value));
click$.pipe(
concatMap(() => interval(1000).pipe(take(3))) // Runs one at a time
).subscribe(value => console.log('ConcatMap:', value));
3. Filtering Operators
✅ Emit only specific values.
Operator Description
ts
of(1, 2, 3, 4, 5, 6)
.pipe(filter(num => num % 2 === 0)) // Keep only even numbers
.subscribe(value => console.log(value)); // 2, 4, 6
52/330
Example: debounceTime() in a Search Input
ts
fromEvent(searchBox, 'input')
.pipe(
debounceTime(500),
map(event => event.target.value)
)
.subscribe(value => console.log('Search:', value));
4. Combination Operators
✅ Combine multiple Observables.
Operator Description
forkJoin() Waits for all Observables to complete and emits results as an array.
withLatestFrom() Combines with another Observable but only emits when the primary
Observable emits.
ts
53/330
combineLatest([obs1, obs2]).subscribe(([num, letter]) => {
console.log(`Number: ${num}, Letter: ${letter}`);
});
failingObservable.pipe(
catchError(err => of('Fallback value')) // Return a fallback value
).subscribe(value => console.log(value));
6. Utility Operators
✅ Perform side effects.
54/330
Operator Description
of(1, 2, 3)
.pipe(
tap(value => console.log('Side Effect:', value))
)
.subscribe(value => console.log('Emitted:', value));
7. Multicasting Operators
✅ Share Observables among multiple subscribers.
Operator Description
ts
55/330
setTimeout(() => sharedObservable.subscribe(value => console.log('Subscriber 2:',
value)), 3000);
Conclusion
✔ Creation Operators create Observables ( of() , from() ).
✔ Transformation Operators modify values ( map() , switchMap() ).
✔ Filtering Operators refine data ( filter() , debounceTime() ).
✔ Combination Operators merge Observables ( combineLatest() , zip() ).
✔ Error Handling Operators manage errors ( catchError() , retry() ).
✔ Utility Operators assist with debugging ( tap() , delay() ).
✔ Multicasting Operators share Observables ( share() , shareReplay() ).
Sure! Let's go through some real-world Angular examples using RxJS operators. These
examples will cover:
✅ Use Case: When a user types in a search box, we should cancel previous API calls and only
fetch the latest query result.
56/330
ts
@Component({
selector: 'app-search',
template: `
<input [formControl]="searchControl" placeholder="Search for users" />
<ul>
<li *ngFor="let user of users">{{ user.name }}</li>
</ul>
`
})
export class SearchComponent {
searchControl = new FormControl('');
users: any[] = [];
✅ Why switchMap() ? It cancels previous requests and only processes the latest one,
preventing unnecessary API calls.
✅ Use Case: Validate input fields only after the user stops typing to reduce server load.
Example: Email Validation
57/330
ts
@Component({
selector: 'app-email-check',
template: `
<input [formControl]="emailControl" placeholder="Enter email" />
<p *ngIf="message">{{ message }}</p>
`
})
export class EmailCheckComponent {
emailControl = new FormControl('');
message = '';
✅ debounceTime(500) ensures API calls are made only when the user pauses typing.
✅ Use Case: Fetch live data (e.g., stock prices, notifications) at regular intervals.
Example: Fetching Stock Prices Every 5 Seconds
ts
58/330
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { interval } from 'rxjs';
import { switchMap } from 'rxjs/operators';
@Component({
selector: 'app-stock-price',
template: `<p>Stock Price: {{ price }}</p>`
})
export class StockPriceComponent {
price: number = 0;
✅ Use Case: Fetch data from multiple APIs and wait until all are completed.
Example: Fetch User Details and Posts Together
ts
@Component({
selector: 'app-user-details',
template: `
<h3>{{ user?.name }}</h3>
<h4>Posts:</h4>
59/330
<ul>
<li *ngFor="let post of posts">{{ post.title }}</li>
</ul>
`
})
export class UserDetailsComponent {
user: any;
posts: any[] = [];
✅ forkJoin() ensures that both API calls finish before displaying data.
✅ Use Case: Show fallback data or a user-friendly error message when an API request fails.
Example: Handling API Errors Gracefully
ts
@Component({
selector: 'app-error-handling',
template: `<p>{{ message }}</p>`
})
export class ErrorHandlingComponent {
60/330
message = '';
ts
@Injectable({
providedIn: 'root'
})
export class AuthService {
private userSubject = new BehaviorSubject<any>(null);
user$ = this.userSubject.asObservable();
login(user: any) {
this.userSubject.next(user);
}
logout() {
this.userSubject.next(null);
61/330
}
}
@Component({
selector: 'app-navbar',
template: `<p *ngIf="user">Welcome, {{ user.name }}</p>`
})
export class NavbarComponent {
user: any;
✅ Useful for managing authentication states without needing @Input() and @Output() .
🔹 Summary
✔ Efficient API calls: switchMap() for user search, debounceTime() for validation
✔ Live updates: interval() for real-time stock prices
✔ Parallel API calls: forkJoin() for fetching multiple resources
✔ Error handling: catchError() for graceful fallback
✔ State management: BehaviorSubject for global state
62/330
State Management in Angular – A
Detailed Guide
State management is a crucial concept in Angular applications, ensuring that different parts
of an application can access and update shared data consistently. This guide will explain
state management with examples and diagrams, covering:
Example Scenario:
Consider a shopping cart in an e-commerce application:
63/330
2️⃣ Types of State in Angular
Angular applications have two types of state:
+---------------------------+
| 🏠 HomeComponent |
| Cart Count: 2 |
+---------------------------+
⬇ (Shared State)
+---------------------------+
| 🛒 CartComponent |
| Items in Cart: 2 |
+---------------------------+
64/330
4️⃣ Implementing State Management in Angular
🔹 Method 1: Using Service with BehaviorSubject (Best for Small &
Medium Apps)
✅ Pros: Simple, no external libraries, and uses RxJS.
❌ Cons: Manual state management.
Example: Implementing a Shopping Cart Service
ts
@Injectable({
providedIn: 'root'
})
export class CartService {
private cartItems = new BehaviorSubject<number>(0);
cartItems$ = this.cartItems.asObservable();
addToCart() {
this.cartItems.next(this.cartItems.value + 1);
}
}
ts
@Component({
selector: 'app-cart-button',
template: `<button (click)="addItem()">Add to Cart</button>`
})
export class CartButtonComponent {
constructor(private cartService: CartService) {}
65/330
addItem() {
this.cartService.addToCart();
}
}
ts
@Component({
selector: 'app-cart-display',
template: `<p>Cart Items: {{ cartCount }}</p>`
})
export class CartDisplayComponent {
cartCount = 0;
✅ Now, whenever a user clicks "Add to Cart", the cart count updates across all
components.
66/330
npm install @ngrx/store
ts
ts
ts
@NgModule({
imports: [StoreModule.forRoot({ count: counterReducer })],
})
export class AppModule {}
67/330
ts
@Component({
selector: 'app-counter',
template: `
<p>Counter: {{ count$ | async }}</p>
<button (click)="increase()">+</button>
<button (click)="decrease()">-</button>
<button (click)="reset()">Reset</button>
`
})
export class CounterComponent {
count$ = this.store.select('count');
increase() { this.store.dispatch(increment()); }
decrease() { this.store.dispatch(decrement()); }
reset() { this.store.dispatch(reset()); }
}
✅ With NgRx, the state is fully centralized, making debugging and state tracking easier.
Service with RxJS Small to medium apps with simple state sharing
( BehaviorSubject )
NgRx (Redux for Angular) Large-scale apps requiring centralized state management
68/330
🔹 Summary
✔ Service with BehaviorSubject: Simple and effective for small applications.
✔ NgRx: Best for large applications where state management is complex.
✔ Akita: A balance between complexity and structure.
Would you like a comparison with Redux or a practical example for your use case? 😊
Explain Ngrx in detail with diagram
✅ Key Features:
✔️ Centralized state management
✔️ Unidirectional data flow
✔️ Immutability
✔️ Debugging tools (Redux DevTools)
✔️ Side effects handling (NgRx Effects)
🔹 Diagram: NgRx Flow in Angular
rust
69/330
└────────────┘
⬆ ⬇
│ │
└──────── Effect ─────────┘
sh
ts
ts
ts
71/330
import { NgModule } from '@angular/core';
import { StoreModule } from '@ngrx/store';
import { counterReducer } from './counter.reducer';
@NgModule({
imports: [
StoreModule.forRoot({ count: counterReducer }) // Register the reducer
],
})
export class AppModule { }
ts
@Component({
selector: 'app-counter',
template: `
<p>Counter: {{ count$ | async }}</p>
<button (click)="increase()">+</button>
<button (click)="decrease()">-</button>
<button (click)="reset()">Reset</button>
`
})
export class CounterComponent {
count$ = this.store.select('count');
increase() { this.store.dispatch(increment()); }
decrease() { this.store.dispatch(decrement()); }
72/330
reset() { this.store.dispatch(reset()); }
}
🔹 Now, clicking the buttons will update the state, and the UI will reflect changes.
ts
@Injectable()
export class CounterEffects {
logIncrement$ = createEffect(() =>
this.actions$.pipe(
ofType(increment),
tap(() => console.log('Increment action dispatched!'))
),
{ dispatch: false } // Prevents an infinite loop
);
ts
@NgModule({
73/330
imports: [
EffectsModule.forRoot([CounterEffects]) // Register the effect
]
})
export class AppModule {}
sh
ts
@NgModule({
imports: [
StoreDevtoolsModule.instrument({ maxAge: 25 }) // Enables time-travel debugging
]
})
export class AppModule {}
✅ Now, you can track state changes in the Redux DevTools Chrome extension!
74/330
Feature Service with RxJS NgRx
📌 Would you like an example of NgRx for real-world applications like Authentication or
Shopping Cart? 😊
yes please
sh
75/330
2️⃣ Define Authentication Actions ( auth.actions.ts )
ts
// Login action
export const login = createAction(
'[Auth] Login',
props<{ email: string; password: string }>()
);
// Logout action
export const logout = createAction('[Auth] Logout');
ts
76/330
user: any;
loading: boolean;
error: string | null;
}
ts
@NgModule({
imports: [
StoreModule.forRoot({ auth: authReducer })
]
})
export class AppModule { }
77/330
5️⃣ Implement Authentication Effects ( auth.effects.ts )
ts
@Injectable()
export class AuthEffects {
login$ = createEffect(() =>
this.actions$.pipe(
ofType(login),
mergeMap(action =>
this.authService.login(action.email, action.password).pipe(
map(user => loginSuccess({ user })),
catchError(error => of(loginFailure({ error: 'Login failed' })))
)
)
)
);
ts
78/330
// Simulating an API call (replace with actual HTTP request)
if (email === 'user@example.com' && password === 'password') {
return of({ id: 1, name: 'John Doe', email });
} else {
throw new Error('Invalid credentials');
}
}
}
ts
@NgModule({
imports: [
EffectsModule.forRoot([AuthEffects])
]
})
export class AppModule { }
This component connects with the NgRx store to trigger authentication actions.
ts
@Component({
79/330
selector: 'app-login',
template: `
<div>
<h2>Login</h2>
<input type="email" [(ngModel)]="email" placeholder="Email">
<input type="password" [(ngModel)]="password" placeholder="Password">
<button (click)="onLogin()">Login</button>
onLogin() {
this.store.dispatch(login({ email: this.email, password: this.password }));
}
}
ts
@Component({
80/330
selector: 'app-logout',
template: `
<div>
<h2>Welcome, {{ user$ | async?.name }}</h2>
<button (click)="onLogout()">Logout</button>
</div>
`
})
export class LogoutComponent {
user$ = this.store.select(state => state.auth.user);
onLogout() {
this.store.dispatch(logout());
}
}
ts
81/330
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
@NgModule({
imports: [
StoreDevtoolsModule.instrument({ maxAge: 25 })
]
})
export class AppModule { }
✔ Now, you can track actions and state changes in real-time using Redux DevTools in
Chrome.
📌 Final Thoughts
✅ NgRx is a great choice for managing authentication, shopping carts, or large-scale
applications.
✅ Using Effects, we efficiently handle API calls and asynchronous operations.
✅ Selectors can be used to retrieve specific parts of the state efficiently.
📌 Would you like another real-world example, such as Shopping Cart or Role-Based
Authentication? 😊
82/330
1️⃣ Local Component State (Using @Input and @Output)
How It Works?
Each component manages its own state.
Example:
ts
@Component({
selector: 'child-component',
template: `<p>{{ data }}</p>`
})
export class ChildComponent {
@Input() data!: string;
}
ts
@Component({
selector: 'parent-component',
template: `<child-component [data]="parentData"></child-component>`
})
export class ParentComponent {
parentData = 'Hello from Parent!';
}
Pros ✅
✔️ Simple & lightweight for small applications.
✔️ No external dependencies.
Cons ❌
❌ Difficult to scale for large applications.
❌ Deep component nesting leads to prop drilling.
Best for: Small applications with limited state needs.
83/330
2️⃣ Service-based State Management (Using RxJS
BehaviorSubject)
How It Works?
State is managed in an Angular Service.
Example:
ts
login() { this.authState.next(true); }
logout() { this.authState.next(false); }
}
ts
@Component({
selector: 'app-login',
template: `<button (click)="login()">Login</button>`
})
export class LoginComponent {
constructor(private authService: AuthService) {}
login() { this.authService.login(); }
}
Pros ✅
✔️ Simple, fast, and lightweight.
✔️ Works well for medium-sized applications.
✔️ Less boilerplate than NgRx.
Cons ❌
❌ State is not centralized, making debugging harder.
❌ As the app grows, managing multiple services gets complex.
84/330
Best for: Medium-sized apps needing shared state without complex
features.
Pros ✅
✔️ Centralized state for large apps.
✔️ Time-travel debugging via Redux DevTools.
✔️ Immutable state prevents unintended mutations.
✔️ Effects help manage side effects (API calls, async operations).
Cons ❌
❌ Complex setup and boilerplate.
❌ Can be overhead for small apps.
Best for: Enterprise-level apps with complex state & high scalability.
Example:
ts
login() { this.isAuthenticated.set(true); }
logout() { this.isAuthenticated.set(false); }
}
Pros ✅
✔️ More efficient than RxJS (direct state mutation).
✔️ Eliminates unnecessary re-renders.
✔️ Less boilerplate than NgRx.
Cons ❌
❌ Still new, not widely adopted yet.
Best for: Future Angular apps needing reactive performance without
NgRx overhead.
86/330
Approach Best for Pros Cons
Angular Signals (Angular 16+) Future apps Efficient, less New, not widely
boilerplate adopted
📌 Final Take:
If you're working on a large app that requires time-travel debugging, structured state
management, and immutability, NgRx is the most scalable and efficient solution. However,
if performance and simplicity are your priority, Signals-based state management is the
future.
88/330
The total price updates automatically.
ts
@Injectable({
providedIn: 'root'
})
export class CartService {
// 🟢 Define a signal to hold cart items
private cartItems = signal<CartItem[]>([]);
89/330
// ❌ Remove item from cart
removeItem(id: number) {
this.cartItems.update(items => items.filter(item => item.id !== id));
}
}
cart.component.ts
ts
@Component({
selector: 'app-cart',
templateUrl: './cart.component.html',
})
export class CartComponent {
constructor(private cartService: CartService) {}
90/330
}
}
cart.component.html
html
<h2>Shopping Cart</h2>
<ul>
<li *ngFor="let item of cart()">
{{ item.name }} - ₹{{ item.price }}
<button (click)="removeItem(item.id)">Remove</button>
</li>
</ul>
product-list.component.ts
ts
@Component({
selector: 'app-product-list',
91/330
templateUrl: './product-list.component.html',
})
export class ProductListComponent {
constructor(private cartService: CartService) {}
addToCart() {
const newItem = { id: Date.now(), name: 'Laptop', price: 50000 };
this.cartService.addItem(newItem);
}
}
product-list.component.html
html
<h2>Products</h2>
<button (click)="addToCart()">Add Laptop to Cart</button>
92/330
🛠️ Summary
✅ Signals provide a lightweight, reactive alternative to RxJS & NgRx.
✅ Perfect for local and global state management in medium-to-large apps.
✅ More performance-efficient than traditional Angular approaches.
✅ Reduces complexity & boilerplate, making state management easier.
93/330
Angular Router allows us to navigate between pages and retrieve route parameters
dynamically. With Signals, we can make this process more reactive and efficient.
ts
ts
@Component({
selector: 'app-product-detail',
templateUrl: './product-detail.component.html',
})
export class ProductDetailComponent {
private route = inject(ActivatedRoute); // Inject ActivatedRoute
94/330
// 🟢 Computed Signal to check if the product exists
isProductValid = computed(() => this.productId() !== null);
goBack() {
this.router.navigate(['/products']);
}
}
🔹 product-detail.component.html
html
<h2>Product Details</h2>
<p *ngIf="isProductValid()">Product ID: {{ productId() }}</p>
<button (click)="goBack()">Back to Products</button>
json
95/330
Step 1: Create a Signal-based API Service
We’ll create a ProductService that:
🔹 product.service.ts
ts
@Injectable({
providedIn: 'root',
})
export class ProductService {
private apiUrl = 'https://api.example.com/products';
🔹 product-detail.component.ts
ts
96/330
import { Component, inject, signal } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ProductService } from '../services/product.service';
@Component({
selector: 'app-product-detail',
templateUrl: './product-detail.component.html',
})
export class ProductDetailComponent {
private route = inject(ActivatedRoute);
private productService = inject(ProductService);
constructor() {
const id = Number(this.route.snapshot.paramMap.get('id'));
if (id) {
this.productService.fetchProduct(id);
}
}
}
🔹 product-detail.component.html
html
<h2>Product Details</h2>
<p *ngIf="product()">Product Name: {{ product()?.name }}</p>
<p *ngIf="product()">Price: ₹{{ product()?.price }}</p>
97/330
No memory leaks (RxJS subscriptions need manual cleanup).
Update product-detail.component.ts
ts
@Component({
selector: 'app-product-detail',
templateUrl: './product-detail.component.html',
})
export class ProductDetailComponent {
private route = inject(ActivatedRoute);
private productService = inject(ProductService);
constructor() {
// Reactively track route changes and fetch product
effect(() => {
const id = Number(this.route.snapshot.paramMap.get('id'));
if (id) {
this.productId.set(id);
this.productService.fetchProduct(id);
}
});
98/330
}
}
📌 Summary
✅ Using Signals with Router eliminates manual subscriptions.
✅ Signals with HTTP Requests automatically update UI when API data changes.
✅ Using effect()helps track route changes & API fetches seamlessly.
✅ More performant & cleaner than RxJS-based solutions.
99/330
🚀 What’s Next?
Would you like an example of using Signals with Angular Forms or State Management for
Authentication? 🔐
yes.Explain in detail different types of Angular Forms and
then explain the use of signals with Angular Forms and
🛠️
then for Authentication.
Let’s explore each type and then move on to using Signals with Forms and Authentication.
100/330
ts
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, FormsModule], // Import FormsModule
bootstrap: [AppComponent],
})
export class AppModule {}
<label>Email:</label>
<input type="email" name="email" ngModel required>
101/330
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
registerUser(userData: any) {
console.log('User Registered:', userData);
}
}
ts
@NgModule({
imports: [ReactiveFormsModule], // Import ReactiveFormsModule
})
export class AppModule {}
102/330
Step 2: Create Form in app.component.ts
ts
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
userForm = new FormGroup({
name: new FormControl('', Validators.required),
email: new FormControl('', [Validators.required, Validators.email]),
});
registerUser() {
console.log('User Registered:', this.userForm.value);
}
}
html
<label>Email:</label>
<input type="email" formControlName="email">
<span *ngIf="userForm.controls.email.invalid">Valid Email required</span>
103/330
✅ Better state management using FormControl .
✅ Supports dynamic form controls.
✅ Structured and scalable.
ts
@NgModule({
providers: [provideSignalsForm()],
})
export class AppModule {}
ts
104/330
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
name = new FormControlSignal('', { validators: Validators.required });
email = new FormControlSignal('', { validators: [Validators.required,
Validators.email] });
registerUser() {
console.log('User Registered:', { name: this.name.value, email: this.email.value
});
}
}
<label>Email:</label>
<input type="email" [formControl]="email">
<span *ngIf="!email.valid">Valid Email required</span>
105/330
📌 4. Using Signals for Authentication
(Login System)
✅ We’ll create a login system using Signals.
✅ Store user authentication state in a Signal.
✅ Dynamically update UI when the user logs in/out.
ts
@Injectable({
providedIn: 'root',
})
export class AuthService {
user = signal<{ email: string } | null>(null); // 🟢 Auth state
login(email: string) {
this.user.set({ email });
}
logout() {
this.user.set(null);
}
}
ts
106/330
import { Component, inject, signal } from '@angular/core';
import { AuthService } from '../services/auth.service';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
})
export class LoginComponent {
email = signal('');
authService = inject(AuthService);
login() {
this.authService.login(this.email());
}
logout() {
this.authService.logout();
}
}
<h2>Login</h2>
<input type="email" [(ngModel)]="email()" placeholder="Enter email">
<button (click)="login()">Login</button>
<button (click)="logout()">Logout</button>
🚀 107/330
🚀 Summary
Feature Template-Driven Reactive Forms Signals-Based
🔐
Yes. Explain in detail JWT & Signals and their uses
108/330
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJ1c2VySWQiOiIxMjM0IiwidXNlcm5hbWUiOiJqb2huZG9lIn0.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
109/330
import { Injectable, signal, computed } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class AuthService {
private token = signal<string | null>(localStorage.getItem('token')); // 🟢 Auth
State
this.token.set(fakeToken);
localStorage.setItem('token', fakeToken);
}
logout() {
this.token.set(null);
localStorage.removeItem('token');
}
}
110/330
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
})
export class LoginComponent {
email = signal('');
password = signal('');
authService = inject(AuthService);
login() {
this.authService.login(this.email(), this.password());
}
logout() {
this.authService.logout();
}
}
<h2>Login</h2>
<ng-template #loginForm>
<input type="email" [(ngModel)]="email()" placeholder="Email">
<input type="password" [(ngModel)]="password()" placeholder="Password">
<button (click)="login()">Login</button>
</ng-template>
@Injectable({
providedIn: 'root',
})
export class AuthGuard implements CanActivate {
private authService = inject(AuthService);
private router = inject(Router);
canActivate(): boolean {
if (!this.authService.isAuthenticated()) {
this.router.navigate(['/login']);
return false;
}
return true;
}
}
ts
112/330
import { DashboardComponent } from './dashboard/dashboard.component';
import { AuthGuard } from './guards/auth.guard';
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
<nav>
<a routerLink="/dashboard">Dashboard</a>
<button *ngIf="authService.isAuthenticated(); else loginBtn"
(click)="authService.logout()">Logout</button>
<ng-template #loginBtn>
<a routerLink="/login">Login</a>
</ng-template>
</nav>
113/330
📌 4. Full JWT Flow with Signals (Diagram)
plaintext
🚀 Conclusion
🔹 JWT is used for secure authentication in Angular applications.
🔹 Signals provide automatic state management without subscriptions.
🔹 With Signals, authentication state updates automatically across components.
🔹 Combining JWT + Signals + Auth Guards ensures a secure authentication system.
114/330
Would you like to add role-based authentication (Admin/User)? 🚀
🔐
Explain role-based authentication
Role-Based Authentication in
Angular with Signals & JWT
Role-Based Authentication (RBA) ensures that users only access permitted resources based
on their assigned roles (e.g., Admin, User, Editor). In Angular, we can implement RBA
efficiently using JWT, Signals, and Route Guards.
115/330
✅ Stores authentication state and role using Signals.
✅ Handles login, logout, and token storage.
ts
@Injectable({
providedIn: 'root',
})
export class AuthService {
private token = signal<string | null>(localStorage.getItem('token'));
private role = signal<string | null>(localStorage.getItem('role')); // 🛑 Store
User Role
this.token.set(fakeResponse.token);
this.role.set(fakeResponse.role);
localStorage.setItem('token', fakeResponse.token);
localStorage.setItem('role', fakeResponse.role);
}
logout() {
this.token.set(null);
this.role.set(null);
localStorage.removeItem('token');
localStorage.removeItem('role');
}
}
116/330
✅ Signal dynamically updates UI based on user role.
role
✅ JWT payload should contain a claim when implementing real API.
role
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
})
export class LoginComponent {
email = signal('');
password = signal('');
authService = inject(AuthService);
login() {
this.authService.login(this.email(), this.password());
}
logout() {
this.authService.logout();
}
}
117/330
<h2>Login</h2>
<ng-template #loginForm>
<input type="email" [(ngModel)]="email()" placeholder="Email">
<input type="password" [(ngModel)]="password()" placeholder="Password">
<button (click)="login()">Login</button>
</ng-template>
@Injectable({
providedIn: 'root',
})
export class RoleGuard implements CanActivate {
private authService = inject(AuthService);
private router = inject(Router);
118/330
}
return true;
}
}
✅ Checks if the user has the correct role before accessing a route.
✅ Redirects unauthorized users to an "Unauthorized" page.
ts
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
119/330
✅ Admin can only access /admin-dashboard .
✅ User can only access /user-dashboard .
<nav>
<a routerLink="/user-dashboard" *ngIf="authService.isUser()">User Dashboard</a>
<a routerLink="/admin-dashboard" *ngIf="authService.isAdmin()">Admin Dashboard</a>
<button *ngIf="authService.isAuthenticated(); else loginBtn"
(click)="authService.logout()">Logout</button>
<ng-template #loginBtn>
<a routerLink="/login">Login</a>
</ng-template>
</nav>
120/330
📌 4. Why Use Signals Over BehaviorSubject?
Feature Signals BehaviorSubject
🚀 Conclusion
🔹 Role-Based Authentication ensures users can only access authorized resources.
🔹 JWT tokens contain role claims, which Angular reads to manage access.
🔹 Auth Guards protect role-specific routes dynamically.
🔹 Using Signals, authentication state updates automatically across components.
Would you like to implement Multi-Role Authentication (Admin, User, Manager, etc.)? 🚀
🚀
yes.
Multi-Role Authentication in
Angular Using JWT, Signals & Guards
🔑 Overview
Multi-role authentication extends role-based authentication by supporting multiple roles
(e.g., Admin, User, Manager, Guest). Each user can have one or more roles that determine
which routes, UI elements, and API features they can access.
🛠 Key Features:
121/330
✅ JWT Authentication (Server issues a token with multiple roles).
✅ Role-Based Access Control (RBAC) (Restrict features & routes based on roles).
✅ Route Guards (Only allow users with correct roles).
✅ Signals for Reactive State Management (Auto-update UI & permissions).
@Injectable({
122/330
providedIn: 'root',
})
export class AuthService {
private token = signal<string | null>(localStorage.getItem('token'));
private roles = signal<string[]>(JSON.parse(localStorage.getItem('roles') ||
'[]'));
this.token.set(fakeResponse.token);
this.roles.set(fakeResponse.roles);
localStorage.setItem('token', fakeResponse.token);
localStorage.setItem('roles', JSON.stringify(fakeResponse.roles));
}
logout() {
this.token.set(null);
this.roles.set([]);
localStorage.removeItem('token');
localStorage.removeItem('roles');
}
123/330
✅ Supports multiple roles (e.g., ['admin', 'manager'] ).
✅ Uses for reactive UI updates.
computed()
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
})
export class LoginComponent {
email = signal('');
password = signal('');
authService = inject(AuthService);
login() {
this.authService.login(this.email(), this.password());
}
logout() {
this.authService.logout();
}
}
124/330
<h2>Login</h2>
<ng-template #loginForm>
<input type="email" [(ngModel)]="email()" placeholder="Email">
<input type="password" [(ngModel)]="password()" placeholder="Password">
<button (click)="login()">Login</button>
</ng-template>
@Injectable({
providedIn: 'root',
})
export class RoleGuard implements CanActivate {
private authService = inject(AuthService);
private router = inject(Router);
125/330
return false;
}
return true;
}
}
@NgModule({
imports: [RouterModule.forRoot(routes)],
126/330
exports: [RouterModule],
})
export class AppRoutingModule {}
html
<nav>
<a routerLink="/admin-dashboard" *ngIf="authService.isAdmin()">Admin</a>
<a routerLink="/manager-dashboard" *ngIf="authService.isManager()">Manager</a>
<a routerLink="/user-dashboard" *ngIf="authService.isUser()">User</a>
<button *ngIf="authService.isAuthenticated(); else loginBtn"
(click)="authService.logout()">Logout</button>
<ng-template #loginBtn>
<a routerLink="/login">Login</a>
</ng-template>
</nav>
127/330
Clicks Login Server Verifies Token Sent to Routes Protected
(AuthService) Credentials Client & Stored Based on Role
🚀 Conclusion
🔹 Supports multiple roles per user.
🔹 Uses JWT with role claims.
🔹 Signals provide reactive state management.
🔹 Auth Guards restrict access dynamically.
Would you like to integrate role-based permissions for UI components next? 🚀
🔐
yes
Role-Based UI Permissions in
Angular with JWT & Signals
In addition to restricting routes, we also need to hide/show UI elements dynamically based
on the user’s roles. Let’s implement role-based UI permissions using Angular Signals,
Directives, and Guards.
128/330
Role Access Level UI Elements (Visible)
🔹 This directive hides or shows UI elements dynamically based on the user's role.
🔹 Uses AuthService & Signals for real-time updates.
ts
@Directive({
selector: '[hasRole]',
})
export class HasRoleDirective {
private authService = inject(AuthService);
private allowedRoles = signal<string[]>([]); // Store allowed roles for this
element
@Input()
set hasRole(roles: string[]) {
this.allowedRoles.set(roles);
this.updateView();
129/330
}
private updateView() {
const userRoles = this.authService.roles(); // Get current user roles
📌 Navbar ( navbar.component.html )
html
<nav>
<a routerLink="/admin-dashboard" *hasRole="['admin']">Admin</a>
<a routerLink="/manager-dashboard" *hasRole="['manager', 'admin']">Manager</a>
<a routerLink="/user-dashboard" *hasRole="['user', 'admin', 'manager']">User</a>
<ng-template #loginBtn>
<a routerLink="/login">Login</a>
130/330
</ng-template>
</nav>
html
<h1>Admin Dashboard</h1>
html
131/330
📌 3. Bonus: Restrict API Calls Based on Roles
Even if the UI hides buttons, users could still manually call the API. To prevent this, we
verify roles on the backend.
js
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
if (!roles.some(role => decoded.roles.includes(role))) {
return res.status(403).json({ message: 'Forbidden: Access Denied' });
}
next();
} catch (err) {
return res.status(401).json({ message: 'Invalid Token' });
}
};
132/330
📌 4. Full Authentication & UI Permission Flow (Diagram)
plaintext
🚀 Conclusion
🔹 Uses Signals & Directives for real-time UI updates.
🔹 Hides unauthorized UI elements dynamically.
🔹 Restricts API calls using backend role verification.
🔹 Works seamlessly with Route Guards ( ).
RoleGuard
Would you like to add dynamic role assignment for users next? 🚀
Explain Forms in detail with examples for Reactive Forms
and Template-driven forms.Form Array, FormGroup,
FormBuilder etc.
2. Reactive Forms (More powerful, provides better control over form validation and state)
133/330
📌 1. Template-Driven Forms (Simpler Approach)
🔹 Suitable for small, simple forms.
🔹 Uses Angular directives like .
ngModel
🔹 Data is bound directly to the template (HTML).
🔹 Uses FormsModule (must be imported).
ts
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, FormsModule],
bootstrap: [AppComponent],
})
export class AppModule {}
📌 Example: app.component.html
html
134/330
<label>Email:</label>
<input type="email" name="email" ngModel required />
<br />
<label>Age:</label>
<input type="number" name="age" ngModel />
<br />
📌 Example: app.component.ts
ts
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
onSubmit(form: NgForm) {
console.log('Form Data:', form.value);
}
}
ts
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, ReactiveFormsModule],
bootstrap: [AppComponent],
})
export class AppModule {}
📌 Example: app.component.ts
ts
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
136/330
export class AppComponent {
userForm = new FormGroup({
name: new FormControl('', [Validators.required]),
email: new FormControl('', [Validators.required, Validators.email]),
age: new FormControl(''),
});
onSubmit() {
console.log('Form Data:', this.userForm.value);
}
}
📌 Example: app.component.html
html
<label>Email:</label>
<input type="email" formControlName="email" />
<div *ngIf="userForm.get('email')?.invalid && userForm.get('email')?.touched">
Enter a valid email!
</div>
<br />
<label>Age:</label>
<input type="number" formControlName="age" />
137/330
<br />
ts
138/330
userForm = this.fb.group({
name: ['', Validators.required],
email: ['', [Validators.required, Validators.email]],
age: [''],
});
get skills() {
return this.userForm.get('skills') as FormArray;
}
addSkill() {
this.skills.push(new FormControl(''));
}
removeSkill(index: number) {
this.skills.removeAt(index);
}
📌 Example: app.component.html
html
<form [formGroup]="userForm">
<label>Name:</label>
<input formControlName="name" />
139/330
<br />
<label>Skills:</label>
<div formArrayName="skills">
<div *ngFor="let skill of skills.controls; let i = index">
<input [formControlName]="i" />
<button (click)="removeSkill(i)">Remove</button>
</div>
</div>
<button (click)="addSkill()">Add Skill</button>
</form>
🚀 Conclusion
Feature Template-Driven Forms Reactive Forms
Would you like a real-world example (like a login form with authentication)? 🚀
yes pls with address as a formarray.
Here’s a real-world example of a user registration form with Reactive Forms. This form
includes:
140/330
✅ User details (name, email, password)
✅ Address fields as a FormArray (Users can add/remove multiple addresses)
✅ Form validation (Required fields, email format, password strength)
✅ Submit button disabled when form is invalid
ts
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, ReactiveFormsModule],
bootstrap: [AppComponent],
})
export class AppModule {}
141/330
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
userForm: FormGroup;
this.addresses.push(addressGroup);
}
// Submit form
onSubmit() {
if (this.userForm.valid) {
console.log('Form Data:', this.userForm.value);
142/330
}
}
}
This form allows users to add/remove addresses dynamically and prevents submission until
it is valid.
html
<label>Email:</label>
<input type="email" formControlName="email" />
<div *ngIf="userForm.get('email')?.invalid && userForm.get('email')?.touched">
Enter a valid email!
</div>
<br />
<label>Password:</label>
<input type="password" formControlName="password" />
<div *ngIf="userForm.get('password')?.invalid &&
userForm.get('password')?.touched">
Password must be at least 6 characters long!
</div>
<br />
<h3>Addresses</h3>
<div formArrayName="addresses">
<div *ngFor="let address of addresses.controls; let i = index"
[formGroupName]="i">
<label>Street:</label>
143/330
<input type="text" formControlName="street" />
<label>City:</label>
<input type="text" formControlName="city" />
<label>Country:</label>
<input type="text" formControlName="country" />
<button type="button" (click)="removeAddress(i)">Remove Address</button>
<br /><br />
</div>
</div>
🚀 How it Works
1. The user fills in their name, email, and password.
2. They can add multiple addresses dynamically using the Add Address button.
144/330
{
"name": "John Doe",
"email": "john.doe@example.com",
"password": "password123",
"addresses": [
{
"street": "123 Main St",
"city": "New York",
"country": "USA"
},
{
"street": "456 Second St",
"city": "Los Angeles",
"country": "USA"
}
]
}
🚀 Next Steps
Would you like to see how to save this form data to a backend API or integrate
authentication (JWT)? 😊
yes both.-but backend is java.
2/2
145/330
1️⃣ Submitting Form Data to a Java Backend
📌 Step 1: Create a Spring Boot API for User Registration
Create a new Spring Boot application and define a REST endpoint to receive user data.
java
import java.util.List;
class Address {
private String street;
private String city;
private String country;
java
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/users")
@CrossOrigin(origins = "*") // Allow Angular frontend
146/330
public class UserController {
@PostMapping("/register")
public String registerUser(@RequestBody User user) {
System.out.println("Received user: " + user);
return "User registered successfully!";
}
}
ts
@NgModule({
imports: [HttpClientModule],
})
export class AppModule {}
ts
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
147/330
export class AppComponent {
userForm: FormGroup;
apiUrl = 'http://localhost:8080/api/users/register'; // Backend URL
addAddress() {
this.addresses.push(this.fb.group({
street: ['', Validators.required],
city: ['', Validators.required],
country: ['', Validators.required],
}));
}
removeAddress(index: number) {
this.addresses.removeAt(index);
}
onSubmit() {
if (this.userForm.valid) {
this.http.post(this.apiUrl, this.userForm.value).subscribe(response => {
console.log('Server Response:', response);
});
}
}
}
148/330
✅ Now, when the user submits the form, data is sent to the Java backend!
xml
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
java
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class JwtUtil {
private String secretKey = "mySecretKey"; // Change to a secure key
149/330
return Jwts.builder()
.setSubject(email)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 *
60)) // 1 hour
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
}
java
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/auth")
@CrossOrigin(origins = "*")
public class AuthController {
private final JwtUtil jwtUtil;
150/330
public AuthController(JwtUtil jwtUtil) {
this.jwtUtil = jwtUtil;
}
@PostMapping("/login")
public String login(@RequestBody User user) {
// In real cases, validate user credentials
String token = jwtUtil.generateToken(user.getEmail());
return token;
}
}
ts
getToken() {
return localStorage.getItem('jwtToken');
151/330
}
}
ts
login() {
this.authService.login('user@example.com', 'password123');
}
}
ts
152/330
🚀 Final Workflow
1. User logs in, and Angular stores the JWT token.
🔗 What's Next?
✅ Secure API Endpoints with JWT in Java
✅ Implement Role-Based Authentication in Java & Angular
Would you like me to extend this to Role-Based Access Control (RBAC) using JWT? 😊
Explain Routing and Navigation in Angular 14 and
Angular16+
153/330
🛠️ Step 1: Define Routes
Create a routing module ( app-routing.module.ts ).
ts
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {}
html
<nav>
<a routerLink="/">Home</a>
<a routerLink="/about">About</a>
</nav>
<router-outlet></router-outlet>
154/330
🛠️ Step 3: Navigate Using Router
You can navigate programmatically using the Router service.
ts
navigateToAbout() {
this.router.navigate(['/about']);
}
ts
155/330
3. Lazy Loading with loadComponent() (no need for modules).
ts
✅ No need for DashboardModule ! This reduces the number of files and improves
performance.
156/330
📌 4. Route Guards for Authentication & Authorization
Route Guards protect routes from unauthorized access.
🛡️ Example: auth.guard.ts
ts
canActivate(): boolean {
const isLoggedIn = localStorage.getItem('jwtToken') !== null;
if (!isLoggedIn) {
this.router.navigate(['/login']);
return false;
}
return true;
}
}
ts
157/330
📝 Define Route with Parameter
ts
ngOnInit() {
const userId = this.route.snapshot.paramMap.get('id');
console.log('User ID:', userId);
}
158/330
window.history.pushState({}, '', path);
}
📌 7. Summary
Feature Angular 14 Angular 16+
Standalone ❌ No ✅ Yes
Components
✅ Angular 16+ makes routing simpler, faster, and more modular. Would you like a real-
world example integrating JWT authentication with routing? 🚀
159/330
Routing in Angular allows navigation between different views or pages in a Single Page
Application (SPA). Instead of reloading the page, Angular dynamically swaps components
based on the URL.
ts
160/330
main.ts .
ts
bootstrapApplication(AppComponent, {
providers: [provideRouter(routes)]
});
html
<nav>
<a routerLink="/">Home</a>
<a routerLink="/about">About</a>
</nav>
<router-outlet></router-outlet>
✅ Now, navigating between Home and About pages will dynamically load the
corresponding component without a full page refresh.
161/330
import('./dashboard/dashboard.module').then(m => m.DashboardModule) }
];
✅ This removes the need for dashboard.module.ts , making the application lightweight.
sh
This creates:
ts
@Component({
standalone: true,
selector: 'app-contact',
162/330
template: `<h2>Contact Page</h2>`,
})
export class ContactComponent {}
163/330
const routes: Routes = [
{ path: 'dashboard', loadComponent: () =>
import('./dashboard/dashboard.component').then(m => m.DashboardComponent),
canActivate: [AuthGuard] }
];
@Component({
standalone: true,
selector: 'app-profile',
template: `<h2>Profile ID: {{ profileId }}</h2>`,
})
export class ProfileComponent {
profileId = '';
164/330
📌 7. Using Signals in Routing (Angular 16+)
What are Signals?
Signals allow reactive state management without Observables.
html
Standalone ❌ No ✅ Yes
Components
✅ Angular 16+ improves routing by making it modular, faster, and lightweight. Would
you like an example integrating routing with JWT authentication? 🚀
yes.
2. Backend Validates User → If valid, a JWT token is generated and sent to the client.
4. Protected Routes → When accessing protected routes, the client sends the JWT token in
the request headers.
5. Backend Verifies Token → If valid, access is granted; otherwise, the user is redirected to
login.
166/330
📌 2. Backend (Spring Boot - JWT Authentication API)
This backend will: ✅ Accept login credentials.
✅ Generate JWT token upon successful authentication.
✅ Validate JWT tokens for protected routes.
📍 Step 1: Add Dependencies (Spring Boot Security & JWT)
xml
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import java.util.Date;
import javax.crypto.SecretKey;
167/330
.signWith(SECRET_KEY)
.compact();
}
Jwts.parserBuilder().setSigningKey(SECRET_KEY).build().parseClaimsJws(token);
return true;
} catch (Exception e) {
return false;
}
}
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody AuthRequest request) {
if ("admin".equals(request.getUsername()) &&
"password".equals(request.getPassword())) {
String token = JwtUtil.generateToken(request.getUsername());
return ResponseEntity.ok(new AuthResponse(token));
} else {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid
credentials");
}
}
}
class AuthRequest {
private String username;
168/330
private String password;
// Getters and setters
}
class AuthResponse {
private String token;
public AuthResponse(String token) { this.token = token; }
public String getToken() { return token; }
}
ts
169/330
constructor(private http: HttpClient, private router: Router) {
const token = localStorage.getItem('jwtToken');
if (token) {
this.isAuthenticated.set(true);
this.userRole.set(this.decodeRole(token));
}
}
logout() {
localStorage.removeItem('jwtToken');
this.isAuthenticated.set(false);
this.userRole.set(null);
this.router.navigate(['/login']);
}
170/330
ts
if (!authService.isAuthenticated()) {
router.navigate(['/login']);
return false;
}
return true;
};
ts
171/330
📍 Step 5: Login Component
ts
@Component({
standalone: true,
selector: 'app-login',
template: `
<h2>Login</h2>
<input type="text" [(ngModel)]="username" placeholder="Username">
<input type="password" [(ngModel)]="password" placeholder="Password">
<button (click)="login()">Login</button>
`,
})
export class LoginComponent {
username = '';
password = '';
login() {
this.authService.login(this.username, this.password);
}
}
@Component({
standalone: true,
selector: 'app-dashboard',
template: `<h2>Dashboard</h2><button (click)="logout()">Logout</button>`,
172/330
})
export class DashboardComponent {
constructor(private authService: AuthService) {}
logout() {
this.authService.logout();
}
}
📌 4. Final Thoughts
✅ Uses JWT for authentication.
✅ Protects routes using .
AuthGuard
✅ Utilizes Standalone Components for better performance.
✅ Signals ( ) track authentication state efficiently.
signal()
173/330
3. Client Stores Token → In localStorage or sessionStorage .
java
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import java.util.Date;
import java.util.List;
import javax.crypto.SecretKey;
174/330
return
Jwts.parserBuilder().setSigningKey(SECRET_KEY).build().parseClaimsJws(token).getBody();
}
}
java
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody AuthRequest request) {
if ("admin".equals(request.getUsername()) &&
"password".equals(request.getPassword())) {
String token = JwtUtil.generateToken(request.getUsername(),
List.of("ROLE_ADMIN"));
return ResponseEntity.ok(new AuthResponse(token));
} else if ("user".equals(request.getUsername()) &&
"password".equals(request.getPassword())) {
String token = JwtUtil.generateToken(request.getUsername(),
List.of("ROLE_USER"));
return ResponseEntity.ok(new AuthResponse(token));
} else {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid
credentials");
}
}
}
175/330
📌 3. Frontend - Angular 16+ with Role-Based
Authentication
📍 Step 1: Authentication Service ( auth.service.ts )
ts
logout() {
localStorage.removeItem('jwtToken');
this.isAuthenticated.set(false);
176/330
this.userRole.set(null);
this.router.navigate(['/login']);
}
ts
177/330
📍 Step 3: Define Routes ( app.routes.ts )
ts
@Component({
standalone: true,
selector: 'app-login',
template: `
<h2>Login</h2>
<input type="text" [(ngModel)]="username" placeholder="Username">
178/330
<input type="password" [(ngModel)]="password" placeholder="Password">
<button (click)="login()">Login</button>
`,
})
export class LoginComponent {
username = '';
password = '';
login() {
this.authService.login(this.username, this.password);
}
}
@Component({
standalone: true,
selector: 'app-dashboard',
template: `<h2>User Dashboard</h2><button (click)="logout()">Logout</button>`,
})
export class DashboardComponent {
constructor(private authService: AuthService) {}
logout() {
this.authService.logout();
}
}
📍 Admin Component
179/330
ts
@Component({
standalone: true,
selector: 'app-admin',
template: `<h2>Admin Dashboard</h2>`,
})
export class AdminComponent {}
📍 Unauthorized Component
ts
@Component({
standalone: true,
selector: 'app-unauthorized',
template: `<h2>Access Denied</h2>`,
})
export class UnauthorizedComponent {}
📌 4. Conclusion
✅ JWT authentication with user roles.
✅ Role-based route protection using .
RoleGuard
✅ Standalone components & lazy loading for optimization.
✅ Efficient state management with Signals ( ).
signal()
🚀 Would you like to extend this with role-based UI elements (e.g., show/hide admin links
based on role)?
Component Communication in
Angular (In-Depth Guide)
180/330
In Angular, component communication refers to how different components pass data and
interact with each other. This is essential for building dynamic, maintainable applications.
Parent to Child Passing data from a parent component A parent form passing user
to a child component using @Input() data to a child profile
component
Child to Parent Sending data from a child component A child button component
to a parent component using notifying the parent
@Output() and EventEmitter component when clicked
@Component({
selector: 'app-child',
standalone: true,
181/330
template: `<h3>Welcome, {{ userData.name }}</h3>`,
})
export class ChildComponent {
@Input() userData!: { name: string; age: number };
}
@Component({
selector: 'app-parent',
standalone: true,
imports: [ChildComponent],
template: `
<app-child [userData]="user"></app-child>
`,
})
export class ParentComponent {
user = { name: 'Merin', age: 30 };
}
📌 How it works?
The parent component binds userData to the [userData] input property.
182/330
import { Component, EventEmitter, Output } from '@angular/core';
@Component({
selector: 'app-child',
standalone: true,
template: `<button (click)="sendData()">Click Me</button>`,
})
export class ChildComponent {
@Output() notifyParent = new EventEmitter<string>();
sendData() {
this.notifyParent.emit('Child Clicked the Button!');
}
}
@Component({
selector: 'app-parent',
standalone: true,
imports: [ChildComponent],
template: `
<app-child (notifyParent)="handleChildEvent($event)"></app-child>
<p>{{ message }}</p>
`,
})
export class ParentComponent {
message = '';
handleChildEvent(eventData: string) {
this.message = eventData;
}
}
📌 How it works?
183/330
The child emits an event ( notifyParent.emit() ), and the parent listens for it using
(notifyParent) .
addToCart() {
this.cartCount.set(this.cartCount() + 1);
}
}
@Component({
selector: 'app-product',
standalone: true,
template: `<button (click)="addToCart()">Add to Cart</button>`,
})
export class ProductComponent {
constructor(private cartService: CartService) {}
184/330
addToCart() {
this.cartService.addToCart();
}
}
@Component({
selector: 'app-cart',
standalone: true,
template: `<p>Cart Count: {{ cartService.cartCount() }}</p>`,
})
export class CartComponent {
constructor(public cartService: CartService) {}
}
📌 How it works?
CartService holds a cartCount signal.
185/330
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
login() { this.isLoggedIn.next(true); }
logout() { this.isLoggedIn.next(false); }
}
@Component({
selector: 'app-login',
standalone: true,
template: `<button (click)="login()">Login</button>`,
})
export class LoginComponent {
constructor(private authService: AuthService) {}
login() {
this.authService.login();
}
}
@Component({
selector: 'app-header',
standalone: true,
186/330
template: `<p *ngIf="isLoggedIn">User Logged In</p>`,
})
export class HeaderComponent {
isLoggedIn = false;
📌 How it works?
AuthService manages login state using BehaviorSubject .
📌 7. Conclusion
✅ Standalone components & Signals simplify component communication.
✅ @Input() & @Output() for direct communication.
✅ Services (with RxJS or Signals) for complex state management.
🚀 Would you like a real-world Angular project demonstrating these concepts?
187/330
explain distinctUntil etc features used in Angular.
📌 1. distinctUntilChanged()
🔹 What it does?
Prevents emitting duplicate consecutive values.
ts
@Component({
selector: 'app-search',
template: `<input type="text" placeholder="Search..." id="searchBox">`,
})
export class SearchComponent {
ngOnInit() {
const searchBox = document.getElementById('searchBox') as HTMLInputElement;
fromEvent(searchBox, 'input')
.pipe(
map((event: any) => event.target.value),
debounceTime(300), // Wait for 300ms after last keypress
188/330
distinctUntilChanged() // Ignore if input is the same as last value
)
.subscribe(value => console.log('Searched:', value));
}
}
✅ Use case: Improves performance in live search boxes by avoiding redundant API calls.
📌 2. distinctUntilKeyChanged()
🔹 What it does?
Works like distinctUntilChanged() , but only compares a specific object property.
users$.pipe(distinctUntilKeyChanged('name')).subscribe(console.log);
✅ Use case: Useful in user profile tracking, where only unique names should trigger
updates.
📌 3. distinct()
🔹 What it does?
189/330
Removes all duplicate values, not just consecutive ones.
users$.pipe(distinct()).subscribe(console.log);
✅ Use case: Helps prevent unnecessary updates in dropdown selections or form inputs.
📌 4. Comparison Table
Operator Behavior Use Case
distinct() Filters out all duplicates (not just Dropdown options, API
consecutive ones) responses
190/330
@Component({
selector: 'app-user-search',
template: `<input type="text" (input)="search($event)" placeholder="Search
users...">`,
})
export class UserSearchComponent {
searchSubject = new Subject<string>();
search(event: any) {
this.searchSubject.next(event.target.value);
}
}
✅ Key benefits:
Prevents repeated API calls for the same search query.
📌 Conclusion
distinctUntilChanged() → Prevents consecutive duplicate values.
🚀 Would you like an example integrating these operators into an Angular form?
191/330
yes
ts
@Component({
selector: 'app-user-form',
template: `
<form [formGroup]="userForm">
<label>Email:</label>
<input formControlName="email" placeholder="Enter email">
<div formArrayName="addresses">
<div *ngFor="let address of addresses.controls; let i = index"
[formGroupName]="i">
192/330
<label>City:</label>
<input formControlName="city" placeholder="Enter city">
</div>
</div>
ngOnInit() {
this.userForm = this.fb.group({
email: ['test@example.com', [Validators.required, Validators.email]],
addresses: this.fb.array([
this.fb.group({ city: ['New York'] }),
])
});
193/330
return this.userForm.get('addresses') as FormArray;
}
📌 Explanation
1. Email Field ( distinctUntilChanged() )
Prevents API calls if the user types the same email repeatedly.
✅ Example:
plaintext
Prevents unnecessary updates when only the city field remains the same.
Works inside a FormArray, tracking city updates separately for each address.
✅ Example:
plaintext
User changes:
{ city: "Mumbai" } → { city: "Mumbai" } → { city: "Delhi" }
Console Output: "City changed: Mumbai" (only once), then "City changed:
Delhi"
194/330
📌 Real-World Use Case
In signup forms, where we prevent redundant API calls on repeated input values.
🚀 Would you like me to integrate this with a Java backend using JWT authentication?
Explain ways to share data between 2 projects -the first
project opens the second project using
window.open(url,_blank),
The first project sends data via the URL when opening the second project.
The second project reads the data from the URL parameters.
195/330
id=${userData.id}&name=${encodeURIComponent(userData.name)}`;
window.open(url, '_blank');
ngOnInit() {
this.route.queryParams.subscribe(params => {
console.log('User ID:', params['id']);
console.log('User Name:', params['name']);
});
}
✅ Best for: Small amounts of non-sensitive data (e.g., user ID, language preference).
⚠ Limitations:
🔹 2. Local Storage
How It Works:
196/330
🛠 Example: Retrieving Data in Second Project
ts
Data is stored independently per domain (cannot be shared across different domains).
localStorage does not work across different domains due to browser security
restrictions.
🔹 3. Session Storage
How It Works:
✅ Best for: Temporary session-based data (e.g., login state, form progress).
⚠ Limitations:
197/330
🔹 4. Post Message API (Cross-Origin Communication)
How It Works:
The first project sends data to the second project using window.postMessage() .
setTimeout(() => {
newWindow?.postMessage({ id: 101, name: 'Merin' }, 'https://second-project.com');
}, 3000); // Delay to ensure the new tab loads
🔹 5. Cookies
How It Works:
198/330
The second project reads the cookie.
console.log('User:', cookies['user']);
✅ Best for: Cross-domain data sharing when both projects are on the same parent
domain (e.g., app.example.com and dashboard.example.com ).
⚠ Limitations:
Not recommended for sensitive data (unless using HTTP-Only & Secure cookies with a
backend).
199/330
🛠 Example: Sending Data from First Project (Angular)
ts
sendUserData() {
this.http.post('https://api.example.com/save-user', { id: 101, name: 'Merin'
}).subscribe();
window.open('https://second-project.com', '_blank');
}
ngOnInit() {
this.http.get('https://api.example.com/get-user').subscribe(data => {
console.log('Received Data:', data);
});
}
📌 Summary Table
200/330
Method Cross-Domain? Secure? Persistent? Best Use Case
Cookies ✅ Yes (if same ✅ Yes (if ✅ Yes Authentication tokens, user
domain) HttpOnly ) preferences
201/330
Server-Side Rendering (SSR) in Angular for SEO &
Performance
Server-Side Rendering (SSR) is a technique where web pages are rendered on the server
before being sent to the client. In Angular, SSR is implemented using Angular Universal,
significantly improving SEO and initial load times.
3. Better Social Media Previews → Platforms like Facebook, Twitter, and WhatsApp fetch
metadata.
4. Reduced Time to First Paint (TTFP) → Faster rendering means a better user experience.
5. Works for Slow Networks & Weak Devices → Less JavaScript processing required on the
client.
sh
ng add @nguniversal/express-engine
This command:
202/330
Adds required dependencies ( @nguniversal/express-engine ).
The server.ts file is responsible for rendering Angular on the server. Modify it to include
caching, API handling, and advanced optimizations.
ts
import 'zone.js/node';
import express from 'express';
import { join } from 'path';
import { existsSync } from 'fs';
203/330
console.log(`Server is running on http://localhost:${port}`);
});
sh
Modify your Angular service to check if data exists before making an API call.
✅ app.component.ts
ts
204/330
const API_DATA_KEY = makeStateKey<any>('apiData');
@Component({
selector: 'app-root',
template: `<div *ngIf="data">{{ data }}</div>`
})
export class AppComponent {
data: any;
constructor(
private http: HttpClient,
private state: TransferState,
@Inject(PLATFORM_ID) private platformId: any
) {}
ngOnInit() {
if (this.state.hasKey(API_DATA_KEY)) {
// Use preloaded data from the server
this.data = this.state.get(API_DATA_KEY, null);
} else if (!isPlatformServer(this.platformId)) {
// Fetch data only on the client if not preloaded
this.http.get('https://api.example.com/data').subscribe(response => {
this.data = response;
});
}
}
}
✅ Benefits of TransferState :
Prevents double API calls (one on the server, another on the client).
✅ Modify app-routing.module.ts
205/330
ts
✅ Install Preboot
sh
ts
@NgModule({
imports: [
AppModule,
ServerModule
],
bootstrap: [AppComponent]
})
export class AppServerModule {}
206/330
✅ Preboot Benefits:
Prevents lost interactions (e.g., form submissions).
SSR Setup Uses ng add @nguniversal/express- Same, but optimized for hydration
engine
After Hydration (Angular 16) → The browser simply “hydrates” the existing page.
ts
207/330
]
};
🔥 Benefits of Hydration
Reduces JavaScript execution time.
🎯 Conclusion
1️⃣ Use SSR for SEO, faster initial loading, and improving social sharing.
2️⃣ Optimize SSR with lazy loading, TransferState, caching, and hydration.
3️⃣ Use Hydration (Angular 16+) to avoid reloading server-rendered content.
4️⃣ Mix SSR & CSR based on your application's needs.
🚀 Want help integrating JWT authentication in an SSR-based Angular app? 😃
Explain Core Javascript fundamentals in detail
208/330
🔹 1. JavaScript Basics
🔸 Variables and Data Types
JavaScript uses let , const , and var for declaring variables.
js
Type Example
String "Hello"
Number 42
Null null
Undefined undefined
BigInt 9007199254740991n
Symbol Symbol("id")
✅ Example
js
209/330
let c = true; // Boolean
let d = null; // Null
let e = undefined; // Undefined
🔹 2. Operators in JavaScript
🔸 Arithmetic Operators
js
🔸 Comparison Operators
js
🔸 Logical Operators
js
210/330
🔹 3. Control Flow in JavaScript
🔸 Conditional Statements
js
🔸 Ternary Operator
js
🔸 Switch Statement
js
let day = 3;
switch (day) {
case 1:
console.log("Monday");
break;
case 2:
console.log("Tuesday");
break;
case 3:
console.log("Wednesday");
break;
default:
console.log("Invalid day");
}
211/330
🔹 4. Loops in JavaScript
🔸 For Loop
js
🔸 While Loop
js
let i = 1;
while (i <= 5) {
console.log("Iteration:", i);
i++;
}
🔸 Do-While Loop
js
let j = 1;
do {
console.log("Iteration:", j);
j++;
} while (j <= 5);
🔹 5. Functions in JavaScript
🔸 Function Declaration
js
212/330
function greet(name) {
return `Hello, ${name}!`;
}
console.log(greet("Alice"));
🔸 Function Expression
js
🔹 6. Objects in JavaScript
🔸 Object Creation
js
let person = {
name: "Alice",
age: 30,
greet: function () {
console.log(`Hello, my name is ${this.name}.`);
}
};
person.greet();
🔸 Object Destructuring
213/330
js
🔹 7. Arrays in JavaScript
🔸 Array Creation & Methods
js
🔸 Array Iteration
js
214/330
🔸 Filter
js
🔸 Reduce
js
🔹 9. Asynchronous JavaScript
🔸 Callbacks
js
function fetchData(callback) {
setTimeout(() => {
callback("Data received");
}, 2000);
}
fetchData(console.log);
🔸 Promises
js
🔸 Async/Await
215/330
js
🎯 Conclusion
JavaScript is a powerful, flexible, and widely-used language. Understanding its core
concepts, ES6+ features, and asynchronous programming is essential for modern web
development.
Would you like advanced topics such as closures, prototypes, or event loops explained? 🚀
yes please. in detail all these things
216/330
JavaScript is a powerful, dynamic language that has several advanced concepts that every
developer should master. Below, we’ll cover Closures, Prototypes, the Event Loop, Hoisting,
Scope, and more in great detail.
✅ Example of a Closure
js
function outerFunction(outerVariable) {
return function innerFunction(innerVariable) {
console.log(`Outer Variable: ${outerVariable}`);
console.log(`Inner Variable: ${innerVariable}`);
};
}
Output:
sql
2️⃣ 217/330
2️⃣ Prototypes & Prototypal
Inheritance
🔹 What is a Prototype?
In JavaScript, objects can inherit properties from other objects through a mechanism called
Prototypal Inheritance.
Key Points:
console.log("Start");
setTimeout(() => {
console.log("Timeout Callback");
}, 0);
console.log("End");
Output:
sql
Start
End
Timeout Callback
219/330
Hoisting is JavaScript’s behavior of moving function and variable declarations to the top of
their scope.
✅ Example of Hoisting
js
console.log(a); // Undefined
var a = 5;
console.log(a); // 5
js
var a;
console.log(a); // undefined
a = 5;
console.log(a); // 5
function hello() {
console.log("Hello!");
}
220/330
5️⃣ JavaScript Scope
🔹 Types of Scope
1. Global Scope – Variables accessible anywhere.
3. Block Scope (with let & const ) – Variables inside {} are scoped to that block.
✅ Example of Scope
js
function testScope() {
let functionVar = "I'm inside a function";
console.log(globalVar); // Accessible
console.log(functionVar); // Accessible
}
testScope();
console.log(functionVar); // ❌ Error
👉 Variables declared with var are function-scoped, but let and const are block-
scoped.
function fetchData(callback) {
setTimeout(() => {
221/330
callback("Data received");
}, 2000);
}
fetchData(console.log);
setTimeout(() => {
console.log("Step 1");
setTimeout(() => {
console.log("Step 2");
setTimeout(() => {
console.log("Step 3");
}, 1000);
}, 1000);
}, 1000);
promise.then(console.log);
🔹 Async/Await
js
fetchData().then(console.log);
222/330
👉 Async/Await makes asynchronous code look synchronous!
js
function sayHello() {
console.log(this);
}
sayHello(); // In non-strict mode, refers to Window
🔹 this in Objects
js
const person = {
name: "Alice",
greet: function () {
console.log(`Hello, ${this.name}`);
}
};
person.greet(); // "Hello, Alice"
js
🔹 Throttling
Used to ensure a function executes at most once in a given interval.
js
🎯 Conclusion
224/330
Understanding these advanced JavaScript concepts is crucial for becoming a better
developer.
These topics cover Closures, Prototypes, the Event Loop, Async/Await, Scope, Hoisting,
and more!
Function Variables accessible only within the function where they are declared.
Scope
Block Scope Variables inside {} are only accessible within that block (when using let or
const ).
225/330
✅ Example in JavaScript
js
function showGlobal() {
console.log(globalVar); // Accessible inside the function
}
showGlobal();
console.log(globalVar); // Accessible outside the function as well
Output:
rust
I'm Global
I'm Global
✅ Example in TypeScript
ts
showGlobal();
console.log(globalVar); // Accessible outside the function as well
226/330
✅ JavaScript Function Scope
js
function testFunctionScope() {
var funcVar = "I'm inside a function";
console.log(funcVar); // Accessible here
}
testFunctionScope();
console.log(funcVar); // ❌ Error: funcVar is not defined
🔹 Since var is function-scoped, it is not accessible outside testFunctionScope() .
testFunctionScope();
console.log(funcVar); // ❌ Error: funcVar is not defined
🔹 Same behavior as JavaScript, but with TypeScript’s type enforcement ( string in this
case).
In modern JavaScript (ES6+) and TypeScript, let and const introduce block scope.
function blockScopeExample() {
if (true) {
let blockVar = "I'm inside a block";
227/330
console.log(blockVar); // ✅ Works inside the block
}
console.log(blockVar); // ❌ Error: blockVar is not defined
}
blockScopeExample();
blockScopeExample();
✅ JavaScript Example
js
function testVarLetConst() {
if (true) {
var x = 10;
let y = 20;
const z = 30;
}
console.log(x); // ✅ Accessible (var is function-scoped)
console.log(y); // ❌ Error: y is not defined (block-scoped)
228/330
console.log(z); // ❌ Error: z is not defined (block-scoped)
}
testVarLetConst();
✅ TypeScript Example
ts
🔹 TypeScript adds type safety, but scope behavior remains the same.
console.log(a); // ✅ Undefined
var a: number = 5;
function outer() {
let outerVar = "I'm outer!";
return function inner() {
console.log(outerVar); // ✅ Remembered even after outer() executes
};
}
230/330
const newFunc = outer();
newFunc(); // "I'm outer!"
✅ JavaScript Example
js
let x = 10;
function test() {
let x = 20; // ✅ Shadows outer x
console.log(x); // 20
}
test();
console.log(x); // 10
✅ TypeScript Example
ts
test();
console.log(x); // 10
Hoisting ✅ is hoisted
var ✅ is hoisted
var
🎯 Conclusion
Scope rules are identical in JavaScript and TypeScript.
Always prefer let and const over var for better scope control.
📌 232/330
📌 1. Types of Scope in JavaScript &
TypeScript
There are three types of scope:
Function Variables accessible only inside the function where they are declared.
Scope
Block Scope Variables inside {} are only accessible within that block when using let or
const .
📌 2. Global Scope
A globally scoped variable can be accessed from anywhere in the script.
function showGlobal() {
console.log(globalVar); // ✅ Accessible inside the function
}
showGlobal();
console.log(globalVar); // ✅ Accessible outside the function as well
Output:
rust
I'm Global
I'm Global
233/330
📌 Diagram Representation:
sql
+------------------------+
| Global Scope |
| |
| globalVar -> Accessible|
+------------------------+
↓
+------------------------+
| Function Scope |
| showGlobal() |
| console.log(globalVar) |
+------------------------+
🔹 Since globalVar is in the global scope, it is accessible inside and outside the function.
📌 3. Function Scope
A variable declared with var inside a function is not accessible outside.
function testFunctionScope() {
var funcVar = "I'm inside a function";
console.log(funcVar); // ✅ Accessible here
}
testFunctionScope();
console.log(funcVar); // ❌ Error: funcVar is not defined
📌 Diagram Representation:
sql
234/330
+--------------------------+
| Global Scope |
| |
| console.log(funcVar) ❌ |
+--------------------------+
↓
+--------------------------+
| Function Scope |
| testFunctionScope() |
| funcVar -> Accessible ✅|
+--------------------------+
✅ Example
ts
function blockScopeExample() {
if (true) {
let blockVar = "I'm inside a block";
console.log(blockVar); // ✅ Works inside the block
}
console.log(blockVar); // ❌ Error: blockVar is not defined
}
blockScopeExample();
📌 Diagram Representation:
pgsql
+------------------------+
| Global Scope |
235/330
| |
| console.log(blockVar) ❌|
+------------------------+
↓
+------------------------+
| Block Scope |
| if (true) { |
| blockVar -> Accessible ✅|
+------------------------+
Hoisting Hoisted with undefined Hoisted, but not initialized Hoisted, but not initialized
function testVarLetConst() {
if (true) {
var x = 10;
let y = 20;
const z = 30;
}
console.log(x); // ✅ Accessible (function-scoped)
console.log(y); // ❌ Error (block-scoped)
console.log(z); // ❌ Error (block-scoped)
}
testVarLetConst();
📌 Diagram Representation:
236/330
sql
+------------------------+
| Global Scope |
| console.log(x) ✅ |
| console.log(y, z) ❌ |
+------------------------+
↓
+------------------------+
| Block Scope |
| let y, const z |
| Accessible ✅ only inside|
+------------------------+
📌 6. Hoisting in JavaScript vs
TypeScript
🔹 Hoisting moves declarations to the top but does not move initializations.
✅ Example
ts
📌 Diagram Representation:
javascript
237/330
📌 7. Lexical Scope & Closures
🔹 Lexical Scope means that a function remembers the scope where it was created.
✅ Example
ts
function outer() {
let outerVar = "I'm outer!";
return function inner() {
console.log(outerVar); // ✅ Remembered even after outer() executes
};
}
📌 Diagram Representation:
sql
+----------------------+
| Global Scope |
| newFunc ✅ |
+----------------------+
↓
+----------------------+
| Function Scope |
| outerVar -> Saved ✅|
+----------------------+
📌 8. Shadowing in JavaScript vs
TypeScript
238/330
🔹 Shadowing happens when a variable in an inner scope has the same name as a variable
in an outer scope.
✅ Example
ts
let x = 10;
function test() {
let x = 20; // ✅ Shadows outer x
console.log(x); // 20
}
test();
console.log(x); // 10
📌 Diagram Representation:
sql
+----------------------+
| Global Scope |
| x = 10 |
+----------------------+
↓
+----------------------+
| Function Scope |
| x = 20 (Shadows 10) ✅|
+----------------------+
239/330
Feature JavaScript TypeScript
Hoisting ✅ is hoisted
var ✅ is hoisted
var
🎯 Conclusion
Scope rules are identical in JavaScript and TypeScript.
Always prefer let and const over var for better scoping.
240/330
Types of Version Control Systems (VCS)
There are three main types of version control systems:
Local Version Control Maintains versions on a single machine using simple RCS (Revision
file copying. Control System)
Centralized Version A single central server stores all versions; developers SVN, Perforce,
Control (CVCS) pull changes from it. TFS
Distributed Version Each developer has a local copy of the repository; Git, Mercurial
Control (DVCS) changes can be pushed and pulled from remote
repositories.
241/330
3. Repository → The committed changes are stored.
📌 Diagram Representation:
sql
242/330
git log # Shows commit history
git status # Shows current changes
main
│
├── feature-1 (new branch)
│
├── feature-2 (merged)
243/330
│
└── main (updated)
Commands
sh
GitHub Example
sh
📌 Diagram Representation:
rust
sh
Steps to Resolve
1. Open the conflicted file.
3. Run:
sh
245/330
Reverting and Resetting
Undoing Last Commit
sh
Reverting a Commit
sh
🎯 Summary
✔ Git is the most widely used DVCS.
✔ It allows branching, merging, and collaboration.
✔ Hosting services like GitHub, GitLab, and Bitbucket make remote teamwork easier.
✔ Features like staging, history tracking, and rollback improve code management.
246/330
🚀 Would you like a hands-on demo or deeper dive into CI/CD integration with Git?
Explain CI/CD integration with Git
What is CI/CD?
🔹 Continuous Integration (CI) – Automatically builds and tests code whenever changes are
pushed to the repository.
🔹 Continuous Deployment (CD) – Automatically deploys tested code to production or
staging environments.
📌 CI/CD ensures:
✔ Faster development cycles
✔ Reduced manual errors
✔ Reliable software releases
247/330
Step Description
CI/CD Tools
Popular tools that integrate with Git repositories:
sh
mkdir -p .github/workflows
248/330
yaml
on:
push:
branches:
- main # Runs on push to main branch
pull_request:
branches:
- main # Runs on pull requests to main
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3 # Fetches the repo
deploy:
needs: build # Runs only if the build is successful
runs-on: ubuntu-latest
steps:
- name: Deploy to Server
run: |
echo "Deploying application..."
# Example deployment script (change based on hosting service)
sh
249/330
git add .
git commit -m "Added CI/CD pipeline"
git push origin main
This triggers the GitHub Actions workflow, running tests and deploying automatically.
stages:
- build
- test
- deploy
build:
stage: build
script:
- npm install
- npm run build
test:
stage: test
script:
- npm test
deploy:
stage: deploy
script:
- echo "Deploying to production..."
250/330
git push origin main
sh
groovy
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'npm install'
}
}
stage('Test') {
steps {
sh 'npm test'
}
}
stage('Deploy') {
steps {
sh 'echo Deploying application...'
}
}
}
}
251/330
Step 3: Configure Jenkins
1. Open Jenkins UI.
Deployment Strategies
Strategy Description
Datadog (Monitoring)
Benefits of CI/CD
✅ Faster Releases – Automates the entire process.
✅ Early Bug Detection – Catches issues before they go to production.
252/330
✅ Improved Code Quality – Ensures code consistency with tests.
✅ Reduced Manual Work – Developers focus on coding, not deployments.
Summary
✔ CI/CD automates building, testing, and deploying code
✔ GitHub Actions, GitLab CI/CD, Jenkins, and others integrate with Git
✔ YAML-based pipelines trigger builds on code changes
✔ Monitoring ensures smooth operations
🚀 Would you like a hands-on example of deploying an Angular app with CI/CD?
Explain in detail the new features and update of latest
Angular?
Angular 18, released on May 22, 2024, introduces several significant features and
improvements aimed at enhancing developer experience, application performance, and
interoperability. Here's a detailed overview of the key updates:
BLOG.ANGULAR.DEV
Key Benefits:
Implementation Example:
Developers can utilize Angular Signals to manage state changes without relying on zones:
253/330
typescript
function increment() {
count.set(count() + 1);
}
In this example, the signal function creates a reactive state variable count , and the
increment function updates its value. This approach allows for precise control over when
the UI should reflect state changes.
BLOG.ANGULAR.DEV
SYNCFUSION.COM
Example:
typescript
In this configuration, navigating to the 'dashboard' path dynamically redirects the user to
'user-dashboard' or 'guest-dashboard' based on their authentication status.
254/330
Angular 18 brings improvements to developer tooling, focusing on debugging and server-
side rendering (SSR):
More Readable Stack Traces: Enhancements in stack trace readability simplify the
debugging process, making it easier to trace and resolve issues.
BLOG.ANGULAR.DEV
CDK Enhancements: Updates to the CDK provide developers with more tools and
utilities for building complex components.
BLOG.ANGULAR.DEV
RADIXWEB.COM
RADIXWEB.COM
255/330
7. Firebase App Hosting Integration
Angular 18 simplifies the deployment process by integrating Firebase app hosting directly
into the Angular CLI. This integration allows developers to deploy applications to Firebase
Hosting with minimal configuration, streamlining the deployment workflow and reducing
setup time.
SYNCFUSION.COM
KELLTON.COM
In summary, Angular 18 introduces a host of new features and improvements that enhance
performance, developer experience, and application capabilities. These updates empower
developers to build more efficient, scalable, and user-friendly applications.
Sources
Angular 19, released on November 19, 2024, introduces several significant updates aimed at
enhancing developer experience, application performance, and reactivity. Here's a detailed
overview of the key changes:
BLOG.ANGULAR.DEV
Key Benefits:
256/330
Improved Tree-Shaking: Enhances application performance by allowing more efficient
removal of unused code during the build process.
Implementation Example:
typescript
@Component({
selector: 'app-standalone-component',
templateUrl: './standalone-component.component.html',
styleUrls: ['./standalone-component.component.css'],
standalone: true,
})
export class StandaloneComponent {}
In this example, the standalone: true property designates the component as standalone,
removing the requirement to declare it within an NgModule.
BLOG.ANGULAR.DEV
Key Features:
Server Route Configuration: Allows developers to define routes that are handled
exclusively on the server, optimizing performance for specific use cases.
Event Replay: Ensures that user interactions occurring before full hydration are
seamlessly processed once the client-side JavaScript is fully loaded.
Benefits:
257/330
Improved Performance: Reduces time to interactive by enabling gradual activation of
client-side functionality.
BLOG.ANGULAR.DEV
Key Features:
Benefits:
Implementation Example:
typescript
@Component({
selector: 'app-data-fetcher',
template: `
<div *ngIf="data() as data">
{{ data }}
</div>
`,
258/330
})
export class DataFetcherComponent {
data = httpResource('https://api.example.com/data');
}
In this example, the httpResource function is used to create a reactive data source that the
template can subscribe to, automatically updating the view when new data arrives.
More Intuitive State Management: The updates to the reactivity model provide
developers with more straightforward tools for managing application state. ANGULAR.LOVE
Cleaner Setup Options: The default standalone components simplify project setup and
reduce initial configuration overhead.
Sources
Optimizing Angular applications for performance is crucial for delivering fast and efficient
web applications. Here, we will discuss different techniques such as caching, lazy loading,
and code splitting in detail, with examples.
259/330
1. Caching in Angular Applications
Caching helps in reducing the number of API calls and improving the performance of an
Angular application by storing frequently accessed data.
typescript
@Injectable({
providedIn: 'root',
})
export class CacheInterceptor implements HttpInterceptor {
private cache = new Map<string, any>();
return next.handle(req).pipe(
tap(response => {
this.cache.set(req.url, response);
})
260/330
);
}
}
typescript
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: CacheInterceptor, multi: true }
]
B. Service-Based Caching
Store API responses in a service to prevent redundant calls.
typescript
@Injectable({
providedIn: 'root',
})
export class DataService {
private cache = new Map<string, any>();
261/330
if (this.cache.has(url)) {
return of(this.cache.get(url));
}
return this.http.get(url).pipe(
tap(data => this.cache.set(url, data))
);
}
}
typescript
In dashboard.module.ts
typescript
262/330
@NgModule({
imports: [RouterModule.forChild(routes)],
declarations: [DashboardComponent],
})
export class DashboardModule {}
3. Code Splitting
Angular automatically splits code into smaller bundles using Webpack. However, we can
optimize it further.
C. Dynamic Imports
Load components dynamically to reduce initial bundle size.
typescript
@Component({
selector: 'app-root',
template: `<button (click)="loadComponent()">Load Component</button> <ng-container
#container></ng-container>`,
})
export class AppComponent {
@ViewChild('container', { read: ViewContainerRef }) container!: ViewContainerRef;
263/330
constructor(private resolver: ComponentFactoryResolver) {}
async loadComponent() {
const { LazyComponent } = await import('./lazy.component');
const factory = this.resolver.resolveComponentFactory(LazyComponent);
this.container.clear();
this.container.createComponent(factory);
}
}
typescript
@Component({
selector: 'app-child',
template: `{{ data | json }}`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent {
@Input() data!: any;
}
264/330
5. Using Web Workers for Heavy
Computation
Web workers run scripts in background threads to prevent blocking the UI.
bash
typescript
typescript
265/330
Angular’s build process removes unused code (tree shaking), but further optimization can be
done.
typescript
if (environment.production) {
enableProdMode();
}
bash
ng build --configuration=production
html
266/330
Conclusion
To optimize an Angular application effectively: ✔ Use caching to reduce redundant API calls.
✔ Implement lazy loading and code splitting to load resources only when needed.
✔ Use OnPush change detection and web workers to improve UI responsiveness.
✔ Enable tree shaking, AOT, and production mode for better build performance.
By applying these techniques, you can significantly enhance your Angular application’s speed
and efficiency! 🚀
267/330
Example: Default vs. OnPush Change Detection
typescript
@Component({
selector: 'app-child',
template: `<p>Child Component: {{ data }}</p>`
})
export class ChildComponent {
@Input() data!: string;
}
typescript
@Component({
selector: 'app-child',
template: `<p>Child Component: {{ data }}</p>`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent {
@Input() data!: string;
}
268/330
Parent Component Changes -> Default Child Re-renders
Parent Component Unchanged -> OnPush Child Stays Same
bash
It creates my-worker.worker.ts :
typescript
typescript
269/330
worker.onmessage = ({ data }) => console.log(`Result: ${data}`);
3. Tree Shaking
Tree shaking removes unused JavaScript code from the final bundle, reducing the app size.
270/330
scss
Run:
bash
ng build --configuration=production
JIT Compilation:
Compilation happens at runtime, causing performance issues.
271/330
bash
ng serve
5. Key Takeaways
✔ OnPush Change Detection: Updates components only when needed.
✔ Web Workers: Runs tasks in the background, keeping UI responsive.
✔ Tree Shaking: Removes unused code for a smaller app bundle.
✔ AOT Compilation: Compiles at build time, making apps faster.
✔ JIT Compilation: Used for development, but slower in production.
272/330
It works by analyzing ES6 module imports and exports, removing any unused functions,
classes, or variables that are not referenced in the code.
1. Static Analysis: Identifies which parts of the code are used (live) and which are unused
(dead).
3. Minification and Optimization: The final bundle is minified for better performance.
typescript
// utils.ts
export function usedFunction() {
console.log('This function is used');
}
typescript
// main.ts
import { usedFunction } from './utils';
273/330
usedFunction(); // Calls only usedFunction
What Happens?
The unusedFunction() is never used, but without tree shaking, it might still be
included in the final bundle.
function usedFunction() {
console.log('This function is used');
}
usedFunction();
The unusedFunction() is removed, making the bundle smaller and more efficient.
typescript
Use:
typescript
ng build --configuration=production
This activates:
275/330
Tree shaking
Minification
📌 Install:
bash
📌 Run:
bash
ng build --configuration=production
source-map-explorer dist/my-app/main.js
276/330
Tree Shaking and Lazy Loading
Tree shaking works well with lazy loading in Angular.
Only the necessary modules are loaded, reducing the initial bundle size.
By leveraging tree shaking, lazy loading, and ES6 modules, Angular applications become
highly optimized for performance. 🚀
Explain the different Angular life-cycle hooks in detail
277/330
Here is a summary of all lifecycle hooks in Angular:
@Component({
selector: 'app-child',
template: `<p>Child component: {{ data }}</p>`
278/330
})
export class ChildComponent implements OnChanges {
@Input() data: string = '';
ngOnChanges(changes: SimpleChanges) {
console.log('Previous:', changes['data'].previousValue);
console.log('Current:', changes['data'].currentValue);
}
}
html
<app-child [data]="parentData"></app-child>
typescript
@Component({
selector: 'app-example',
template: `<p>Data: {{ data }}</p>`
})
export class ExampleComponent implements OnInit {
data: string = '';
ngOnInit() {
this.data = 'Component Initialized!';
}
}
279/330
✅ Use Case: Fetch API data, initialize variables.
@Component({
selector: 'app-check',
template: `<p>Counter: {{ counter.value }}</p>`
})
export class CheckComponent implements DoCheck {
counter = { value: 0 };
increment() {
this.counter.value++; // Angular won't detect this change without `ngDoCheck()`
}
ngDoCheck() {
console.log('Change detected!');
}
}
✅ Use Case: Detect changes in mutable objects when normal detection fails.
280/330
📌 Example: Access Projected Content
typescript
@Component({
selector: 'app-content-child',
template: `<ng-content></ng-content>`
})
export class ContentChildComponent implements AfterContentInit {
@ContentChild('projected') content!: ElementRef;
ngAfterContentInit() {
console.log('Projected content:', this.content.nativeElement.textContent);
}
}
html
<app-content-child>
<p #projected>Projected Content</p>
</app-content-child>
✅ Use Case: Access and modify content passed from the parent.
@Component({
281/330
selector: 'app-check-content',
template: `<ng-content></ng-content>`
})
export class CheckContentComponent implements AfterContentChecked {
ngAfterContentChecked() {
console.log('Projected content checked!');
}
}
@Component({
selector: 'app-view',
template: `<p #para>Text to change</p>`
})
export class ViewComponent implements AfterViewInit {
@ViewChild('para') paragraph!: ElementRef;
ngAfterViewInit() {
this.paragraph.nativeElement.style.color = 'red';
}
}
282/330
7. ngAfterViewChecked() - Detect View Changes
Runs after the view (or child components) is checked.
@Component({
selector: 'app-check-view',
template: `<p>{{ text }}</p>`
})
export class CheckViewComponent implements AfterViewChecked {
text = 'Initial text';
ngAfterViewChecked() {
console.log('View checked!');
}
}
@Component({
selector: 'app-destroy',
283/330
template: `<p>Timer running...</p>`
})
export class DestroyComponent implements OnDestroy {
private subscription!: Subscription;
ngOnInit() {
this.subscription = interval(1000).subscribe(val => console.log(val));
}
ngOnDestroy() {
this.subscription.unsubscribe();
console.log('Component destroyed and subscription closed');
}
}
Component Created
├── ngOnChanges() → (Runs when @Input changes)
├── ngOnInit() → (Runs once after first ngOnChanges)
├── ngDoCheck() → (Runs on every change detection cycle)
├── ngAfterContentInit() → (Runs once when content is projected)
├── ngAfterContentChecked() → (Runs on every change detection cycle for projected
content)
├── ngAfterViewInit() → (Runs once when view is initialized)
├── ngAfterViewChecked() → (Runs on every change detection cycle for view)
Component Destroyed
├── ngOnDestroy() → (Runs before component is destroyed)
Final Thoughts
284/330
✔ ngOnInit() - Fetch data, initialize properties.
✔ ngOnChanges() - Detect input property changes.
✔ ngOnDestroy() - Cleanup and prevent memory leaks.
✔ ngAfterViewInit() - Work with child components & DOM.
✔ ngAfterContentInit() - Work with projected content.
1. Emulated (Default) → Uses scoped styles (adds unique attributes to limit CSS scope).
2. ShadowDom → Uses native browser Shadow DOM (styles are fully encapsulated).
typescript
285/330
📌 Example: Emulated Encapsulation
typescript
@Component({
selector: 'app-example',
template: `<p class="text">This is Emulated Encapsulation</p>`,
styles: [`.text { color: blue; }`],
encapsulation: ViewEncapsulation.Emulated
})
export class ExampleComponent {}
✅ Pros:
Prevents CSS conflicts.
❌ Cons:
Doesn't provide full isolation like Shadow DOM.
286/330
typescript
@Component({
selector: 'app-shadow',
template: `<p class="text">This is Shadow DOM</p>`,
styles: [`.text { color: red; }`],
encapsulation: ViewEncapsulation.ShadowDom
})
export class ShadowComponent {}
<app-shadow>
#shadow-root (open)
<p class="text">This is Shadow DOM</p>
</app-shadow>
✅ Pros:
True encapsulation (no style leakage).
❌ Cons:
Not all browsers fully support Shadow DOM.
📌 Example: No Encapsulation
typescript
@Component({
selector: 'app-none',
template: `<p class="text">No Encapsulation</p>`,
287/330
styles: [`.text { color: green; }`],
encapsulation: ViewEncapsulation.None
})
export class NoneComponent {}
✅ Pros:
Useful for global theming.
❌ Cons:
Styles may leak into other components, leading to unexpected styling issues.
ShadowDom Full True isolation Ensures styles don’t leak, follows web
standards
None None Global Useful for global styling but can cause
conflicts
288/330
standards.
🔹 Use None: When applying global styles, but be careful about unintended styling issues.
Parent Component:
typescript
@Component({
selector: 'app-parent',
template: `<app-child></app-child>`,
styles: [`.title { font-size: 30px; color: red; }`],
encapsulation: ViewEncapsulation.Emulated
})
export class ParentComponent {}
Child Component:
typescript
@Component({
selector: 'app-child',
template: `<p class="title">Child Component</p>`,
styles: [`.title { font-size: 15px; color: blue; }`],
encapsulation: ViewEncapsulation.Emulated
})
export class ChildComponent {}
Expected Behavior
With Emulated Mode: The child’s .title style (blue, 15px) is applied only to the child.
With None Mode: The parent’s .title style (red, 30px) overrides the child’s style.
289/330
Conclusion
✔ View Encapsulation in Angular ensures component styles do not affect other parts of
the application.
✔ Default mode ( Emulated ) is the best choice for most cases.
✔ ShadowDom provides full isolation but is limited by browser support.
✔ None can be useful for global styling but risks style leakage.
By understanding View Encapsulation, you can build more maintainable, modular, and
scalable Angular applications! 🚀
What is elvis operator in Typescript.Explain enums and
generics in Typescript.
interface User {
name: string;
address?: {
city: string;
country: string;
};
}
290/330
// Without Elvis Operator - Causes Error
// console.log(user.address.city); // ❌ ERROR: Cannot read properties of undefined
Use Cases
1. Safe Access to Deeply Nested Objects
typescript
typescript
2. Enums in TypeScript
Enums (short for Enumerations) allow you to define a set of named constants in TypeScript.
They improve code readability by giving meaningful names to values.
Types of Enums
1. Numeric Enums (Default)
2. String Enums
typescript
enum Status {
Pending, // 0
InProgress, // 1
Completed // 2
}
console.log(Status.Pending); // Output: 0
console.log(Status[1]); // Output: "InProgress"
enum Status {
Pending = 10,
InProgress = 20,
Completed = 30
}
console.log(Status.Completed); // Output: 30
typescript
enum Role {
Admin = "ADMIN",
User = "USER",
Guest = "GUEST"
}
292/330
3️⃣ Heterogeneous Enums
Enums can contain both numbers and strings.
typescript
enum Mix {
Success = "SUCCESS",
Error = 0
}
typescript
3. Generics in TypeScript
Generics allow creating reusable, type-safe components in TypeScript. They provide
flexibility while ensuring type safety.
293/330
Why Use Generics?
Instead of using any , generics let you define functions, classes, and interfaces that work
with multiple types without losing type safety.
Generics in Interfaces
typescript
interface Box<T> {
value: T;
}
294/330
Generics in Classes
typescript
class DataStorage<T> {
private data: T[] = [];
addItem(item: T) {
this.data.push(item);
}
getItem(index: number): T {
return this.data[index];
}
}
Generics in Functions
typescript
Conclusion
295/330
✔ Elvis Operator ( ?. ) allows safe property access without undefined or null errors.
✔ Enums improve code readability and define named constants.
✔ Generics provide reusable and type-safe code for functions, classes, and interfaces.
🚀 Using these TypeScript features makes your Angular applications more robust and
maintainable!
❌ Cons of RxJS
1. Steep Learning Curve – Too many operators; can be overwhelming.
296/330
4. Performance Overhead – If used excessively, it can impact app performance.
🔹 Using map
typescript
of(1, 2, 3).pipe(
map(value => value * 10)
).subscribe(console.log);
// Output: 10, 20, 30
🔹 Using pluck
typescript
🔹 Using scan
typescript
297/330
import { of } from 'rxjs';
import { scan } from 'rxjs/operators';
of(1, 2, 3, 4).pipe(
scan((acc, curr) => acc + curr, 0)
).subscribe(console.log);
// Output: 1, 3, 6, 10
typescript
of(1, 2, 3, 4, 5).pipe(
filter(value => value % 2 === 0)
).subscribe(console.log);
// Output: 2, 4
🔹 Using catchError
typescript
298/330
throwError(() => new Error("Something went wrong")).pipe(
catchError(err => of("Fallback Value"))
).subscribe(console.log);
// Output: Fallback Value
🔹 Using retry
typescript
🔹 Using finalize
typescript
of("Hello").pipe(
finalize(() => console.log("Stream Completed"))
).subscribe(console.log);
// Output: Hello
// Stream Completed
299/330
typescript
combineLatest([obs1, obs2]).subscribe(console.log);
// Output: [3, "C"] (Only last emitted values)
typescript
// Output:
// Subscriber 1: 1
// Subscriber 1: 2
// Subscriber 1: 3
// Subscriber 2: 3
🔹 BehaviorSubject
300/330
New subscribers get the latest value immediately.
typescript
// Output:
// Subscriber 1: 0
// Subscriber 1: 1
// Subscriber 1: 2
// Subscriber 1: 3
// Subscriber 2: 2
// Subscriber 2: 3
301/330
Feature Cold Observable Hot Observable
concatMap Processes one observable at a time Queued API calls to avoid race
(FIFO). conditions.
mergeMap Runs all inner observables in parallel. Parallel API calls for better
performance.
switchMap Cancels the previous observable when a Live search suggestions (cancels old
new one arrives. requests).
exhaustMap Ignores new values while processing a Form submission prevention (ignores
previous one. multiple clicks).
Examples
🔹 concatMap Example
typescript
of(1, 2, 3).pipe(
concatMap(value => of(`Processed ${value}`).pipe(delay(1000)))
).subscribe(console.log);
// Output: Processed 1 -> Processed 2 -> Processed 3
302/330
🔹 switchMap Example
Cancels previous requests when a new one starts (ideal for autocomplete).
typescript
Conclusion
✔ RxJS is powerful for reactive programming.
✔ Understanding data transformation, error handling, and operators is key to using it
effectively.
✔ Operators like switchMap, concatMap, and mergeMap help control asynchronous logic.
🚀
Explain last 3 questions in detail insetad of table with
examples.
303/330
typescript
// Output:
// Cold Observable Executed
// Subscriber 1: 0.123456
// Cold Observable Executed
// Subscriber 2: 0.987654
Since both subscriptions trigger a new execution, they get different random values.
A typical example is an HTTP request, where each call makes a new request.
typescript
304/330
hotObservable.subscribe(value => console.log('Subscriber 2:', value));
hotObservable.next(20);
// Output:
// Subscriber 1: 10
// Subscriber 1: 20
// Subscriber 2: 20
1️⃣ concatMap()
Use case: Sequential API calls (e.g., saving form steps one by one).
Example of concatMap()
typescript
of(1, 2, 3).pipe(
concatMap(value => of(`Processed ${value}`).pipe(delay(1000)))
).subscribe(console.log);
305/330
// Output (1 second delay between values):
// Processed 1
// Processed 2
// Processed 3
2️⃣ switchMap()
Keeps only the latest value (great for autocomplete, live search).
Use case: Search suggestions (cancels old API requests to save bandwidth).
Example of switchMap()
typescript
clicks.pipe(
switchMap(() => interval(1000))
).subscribe(console.log);
// If the user clicks multiple times, only the latest interval runs.
✅ Best for live search, API requests that should not overlap.
3️⃣ mergeMap()
306/330
Example of mergeMap()
typescript
of(1, 2, 3).pipe(
mergeMap(value => of(`Processed ${value}`).pipe(delay(1000)))
).subscribe(console.log);
✅ Best for making multiple API calls at the same time (e.g., fetching user data and
orders).
4️⃣ exhaustMap()
Example of exhaustMap()
typescript
clicks.pipe(
exhaustMap(() => interval(1000))
).subscribe(console.log);
307/330
// Clicking multiple times will not create multiple intervals.
✅ Best for login buttons, preventing duplicate requests when users spam clicks.
promise.then(console.log);
promise.then(console.log);
// Output:
// Promise Executed
// Promise Result
// Promise Result
308/330
Subscribers get the same result.
observable.subscribe(console.log);
observable.subscribe(console.log);
// Output:
// Observable Executed
// Observable Result
// Observable Executed
// Observable Result
Conclusion
309/330
✔ Cold vs Hot Observables: Cold starts fresh for each subscriber, Hot shares emissions.
✔ Mapping Operators ( switchMap , concatMap , mergeMap , exhaustMap ) help control
asynchronous operations.
✔ Observables vs Promises: Observables provide more flexibility, whereas Promises are
simpler for one-time tasks. 🚀
How to make HTTP Request in Angular?
310/330
What is Angular interceptor?
Angular inject
Angular signals
Angular defer
That's a comprehensive list of Angular topics! I'll go through each one in detail with
explanations, examples, and best practices.
311/330
1. Import HttpClientModule in app.module.ts .
typescript
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
})
export class ExampleComponent implements OnInit {
data: any;
ngOnInit() {
this.http.get('https://jsonplaceholder.typicode.com/posts')
.subscribe(response => {
this.data = response;
});
}
}
✅ Best Practice: Always use services to manage HTTP requests instead of directly in
components.
typescript
312/330
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root' // Available throughout the app
})
export class ApiService {
constructor() { }
}
DI Scopes:
Steps:
typescript
@NgModule({
313/330
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Hook Purpose
Example
typescript
typescript
314/330
import { Component, ViewChild, ElementRef } from '@angular/core';
@Component({
selector: 'app-example',
template: `<button #btn>Click me</button>`
})
export class ExampleComponent {
@ViewChild('btn', { static: true }) button!: ElementRef;
ngOnInit() {
console.log(this.button.nativeElement.textContent); // Outputs: Click me
}
}
✅ Best Practice: Use ViewChild only when necessary to manipulate the DOM.
typescript
315/330
export class ExampleComponent implements OnDestroy {
private subscription!: Subscription;
ngOnInit() {
this.subscription = someObservable.subscribe();
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
typescript
@Component({
selector: 'app-example',
template: `<p>{{ data }}</p>`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ExampleComponent {
@Input() data!: string;
}
316/330
9️⃣ What is the problem with null in async pipe?
The async pipe automatically unsubscribes from observables but initially returns null .
html
or
html
Example
typescript
user$ = this.http.get<User>('/api/user')
.pipe(catchError(err => of({ name: 'Error' })));
Directive Purpose
317/330
Example: Using ngTemplateOutlet
html
Conclusion
We've covered key Angular concepts, including: ✅ Making HTTP Requests
✅ Dependency Injection
✅ Routing
✅ Life Cycle Hooks
✅ Component Communication ( ,
ViewChild )
ViewChildren
✅ Unsubscribing & Change Detection ( )
OnPush
✅ Async Pipe & Error Handling
✅ Directives ( ,
ngContainer ,
ngTemplate )
ngContent
🚀 Next Steps: Let me know which topics you'd like detailed explanations or diagrams for!
What are the advantages of Typescript over JavaScript ?
318/330
Feature TypeScript JavaScript
Modern Features Includes optional chaining, decorators, JavaScript lacks static typing
enums, access modifiers
function add(a, b) {
return a + b;
}
console.log(add(5, "10")); // Output: "510" (unexpected result)
✅ Best Practice: TypeScript helps catch errors early, making it a preferred choice for large-
scale applications.
319/330
Angular provides the assets/ folder to store static files such as images, JSON files, icons,
and fonts.
Default Structure
bash
/src
/assets
/images
/json
/icons
/fonts
/app
angular.json
arduino
/src/assets/config.json
getConfig() {
return this.http.get('/assets/config.json');
}
}
320/330
this.configService.getConfig().subscribe(config => console.log(config));
✅ Best Practice: Use assets/ for static files instead of storing them in src/ or public/ .
Compiler options
json
{
"projects": {
"angular-app": {
"architect": {
"build": {
"options": {
"outputPath": "dist/angular-app",
"assets": ["src/favicon.ico", "src/assets"],
"styles": ["src/styles.css"],
"scripts": []
}
}
}
}
}
}
Key Properties
321/330
Property Description
When it Compiles in the browser at runtime Compiles during the build process
Compiles
Error Detection Errors are found at runtime Errors are found at build time
bash
ng build --prod
bash
322/330
ng build --aot
✅ Best Practice: Always use AOT for production to reduce load time and improve security.
Conclusion
🔹 TypeScript provides better type safety, IDE support, and maintainability over JavaScript.
🔹 Store static assets in the assets/ folder for better organization.
🔹 angular.json manages configurations for building, serving, and optimizing Angular
applications.
🔹 AOT vs. JIT → Use AOT for production and JIT for development.
Would you like a deeper dive into any of these topics? 🚀
1. Selector
A selector in Angular is a custom HTML tag used to define how a component is inserted into
the template. It acts as an identifier for an Angular component.
typescript
@Component({
selector: 'app-user',
template: `<h2>User Component Loaded</h2>`
323/330
})
export class UserComponent { }
The selector app-user can now be used in any HTML template to render this
component.
html
<app-user></app-user>
2. Template
typescript
@Component({
selector: 'app-inline',
template: `<h2>Inline Template Example</h2>`
})
export class InlineComponent { }
typescript
@Component({
selector: 'app-external',
templateUrl: './external.component.html'
})
export class ExternalComponent { }
And in external.component.html :
html
324/330
<h2>External Template Example</h2>
1. What is a Module?
Every Angular application has at least one root module, usually named AppModule .
It defines all the components, directives, and services used within the application.
It is bootstrapped in main.ts .
Example of app.module.ts
typescript
@NgModule({
declarations: [AppComponent, UserComponent], // Declaring components
imports: [BrowserModule], // Importing modules
providers: [], // Services can be added here
bootstrap: [AppComponent] // Bootstrapped component
})
export class AppModule { }
✅ Best Practice: Break down large applications into feature modules using the NgModule
concept.
325/330
Q13: How Does an Angular App Get Loaded & Started?
When an Angular application starts, the following steps occur:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>AngularApp</title>
</head>
<body>
<app-root></app-root> <!-- Root Component -->
</body>
</html>
typescript
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
typescript
326/330
@Component({
selector: 'app-root',
template: `<h1>Welcome to Angular</h1>`
})
export class AppComponent { }
1. Bootstrapped Module
The module that starts the Angular application is called the bootstrapped module.
Example:
typescript
platformBrowserDynamic().bootstrapModule(AppModule)
2. Bootstrapped Component
The first component loaded in the application is called the bootstrapped component.
Example in app.module.ts :
typescript
@NgModule({
bootstrap: [AppComponent] // Bootstrapped Component
327/330
})
export class AppModule { }
Summary
Bootstrapped Module The main module that initializes the app ( AppModule )
✅ Best Practice: Ensure the bootstrapped module is optimized and only includes essential
components for better performance.
Final Summary
1️⃣ Selector → Custom HTML tag used to insert components.
2️⃣ Template → Defines the structure of a component (inline or external).
3️⃣ Module ( app.module.ts) → Main Angular module that organizes components and
services.
4️⃣ App Loading Process → index.html → main.ts→ AppModule→ .
AppComponent
5️⃣ Bootstrapped Module → AppModule, which initializes the Angular app.
6️⃣ Bootstrapped Component → AppComponent , which is the first component to load.
yes
+---------------------------------------------------+
| Browser Loads index.html |
|---------------------------------------------------|
| <app-root></app-root> (Root Component) |
328/330
+---------------------------------------------------+
|
v
+---------------------------------------------------+
| main.ts (Bootstrapper) |
|---------------------------------------------------|
| platformBrowserDynamic().bootstrapModule(AppModule) |
+---------------------------------------------------+
|
v
+---------------------------------------------------+
| app.module.ts (Root Module) |
|---------------------------------------------------|
| @NgModule({ |
| declarations: [AppComponent], |
| imports: [BrowserModule], |
| bootstrap: [AppComponent] |
| }) export class AppModule {} |
+---------------------------------------------------+
|
v
+---------------------------------------------------+
| app.component.ts (Root Component) |
|---------------------------------------------------|
| @Component({ |
| selector: 'app-root', |
| template: `<h1>Welcome to Angular</h1>` |
| }) export class AppComponent {} |
+---------------------------------------------------+
Calls platformBrowserDynamic().bootstrapModule(AppModule) .
329/330
Loads the root module ( AppModule ).
html
<h1>Welcome to Angular</h1>
Key Takeaways
✔ Bootstrapped Module = AppModule (Root Module).
✔ Bootstrapped Component = AppComponent (First Component to Load).
✔ index.html Starts the App by referencing <app-root> .
✔ main.ts Bootstraps the AppModule, which in turn loads the AppComponent .
Would you like any modifications or further details on any part of this? 🚀
330/330