0% found this document useful (0 votes)
3 views81 pages

Angular

Angular is a JavaScript framework developed by Google for building web applications using technologies like HTML, CSS, and JavaScript. It includes features such as Angular CLI for app creation, modules for organization, and various components like directives and pipes for enhancing functionality. The document also covers concepts like single-page vs multi-page applications, TypeScript integration, data binding, routing, interceptors, and guards.

Uploaded by

Sarthak Suman
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views81 pages

Angular

Angular is a JavaScript framework developed by Google for building web applications using technologies like HTML, CSS, and JavaScript. It includes features such as Angular CLI for app creation, modules for organization, and various components like directives and pipes for enhancing functionality. The document also covers concepts like single-page vs multi-page applications, TypeScript integration, data binding, routing, interceptors, and guards.

Uploaded by

Sarthak Suman
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 81

Angular 12+

1) What is Angular ?
• A JavaScript framework for building application using web technologies like html, css and
js.
• Empowers developers to build applications for browsers, mobiles, or desktop.

Angular History:
Developed by Google in 2009, Angular version 1(angular js), 2, 4,5,6,7,8,9,10,11,12,…15 so
on,.
NPM – node package manager, is included with Node. js installation

Angular CLI
• A powerful to create, build, compile and serve Angular2 App
• Used to generate new components, routes, services and pipes
• Command to install angular cli - npm install -g @angular/cli

Angular CLI Commands


Module - ng generate module my-module --> ng g m my-module
Component- ng generate component my-component --> ng g c my-component
Directive - ng generate directive my-directive --> ng g d my-directive
Pipe - ng generate pipe my-pipe --> ng g p my-pipe
Service- ng generate service my-service  ng g s my-service
ng s - builds and serves angular app(serves means hosts in local host 4200 as default one)

Angular Building Blocks


Modules • Components • Templates • Metadata • Data binding • Directives • Pipes
Angular Building Blocks • Routing • Forms • Services • Hooks • Dependency injection

Modules
An Angular module is a class with an @NgModule decorator
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { HeaderComponent } from './header/header.component';
import { FooterComponent } from './footer/footer.component';
import { UserService } from './services/user.service';
import { CapitalizePipe } from './pipes/capitalize.pipe'; // Importing the pipe
import { HoverHighlightDirective } from './directives/hover-highlight.directive'; //
Importing the directive

@NgModule({
declarations: [
AppComponent,
HeaderComponent,
FooterComponent,
CapitalizePipe, // Declaring the pipe
HoverHighlightDirective // Declaring the directive
],
imports: [
BrowserModule,
FormsModule//two way data binding
],
providers: [
UserService
],
bootstrap: [AppComponent]
})
export class AppModule { }

NgModule Metadata Main Properties


• imports – Specify other dependent modules whose classes are required by the component
templates declared in the module
• declarations – Specify the components, directives, and pipes that belong to the module
 providers – Specify the services, accessible across the app
Components

Decorators

• Adds metadata to a class, method, property, or parameter. These are prefix with @ symbol
• Ex: @Component, @NgModule, @Directive, @Pipe etc.
Here, the metadata means:
 selector: The custom HTML tag for the component.
 templateUrl: The path to the component’s HTML template.
 styleUrls: The path to the component’s CSS styles.

2) SPA VS MPA
SPA – Single page application (ex: gmail, google, fb, twitter, github)
• When you visit a specific web page in an SPA, the browser sends a request to the server.
• For the first request, the server sends back an HTML document.
• For subsequent requests, the server sends JSON data instead of a full HTML page.
• The SPA then rewrites the current page’s content using the received data, avoiding the
need to reload the entire web page.
• This behavior makes SPAs feel like native applications, with faster performance and
smoother navigation.
MPA – Multi page application (ex: amazon, ebay, udemy)
• In an MPA, each web page is treated as a separate entity.
• When a user interacts with the application (e.g., clicks a link, submits a form), the server
processes the request and sends back a completely new HTML page.
• The browser then replaces the current page with the newly received page, resulting in a
full page reload.
• This approach prioritizes simplicity and straightforwardness but can lead to slower user
experiences due to frequent page reloads.

3) Angular Typescript
• Super set of JavaScript that compiles into JavaScript
• Developed by Microsoft and released 1.0 version in 2012
• Free and open source programming language
• Advantages: uses both interfaces & classes, Easy to adopt for object oriented developers
(like java & C#) and open source.
Datatypes:
Any, Built-in - number string, Boolean, void, null, undefined,
User Defined - class, interface, Enum, array, function.
Variables:
Var - have function scope or global scope.
var num1 = 1; // Global scope
function exampleFunction() {
var num2 = 2; // Function scope
console.log(num1); // Accessible
console.log(num2); // Accessible
}
exampleFunction();
console.log(num1); // Accessible
console.log(num2); // Error: Cannot find name 'num2'
let - uses block scope
function exampleFunction() {
if (true) {
let x = 10; // x is block-scoped within this if block
console.log(x); // Output: 10
}
// console.log(x); // Error: x is not accessible here
}
exampleFunction();
const – uses block scope
if (true) {
const pi = 3.14; // pi is block-scoped within this if block
// pi = 3.14159; // Error: Cannot reassign a constant variable
console.log(pi); // Output: 3.14
}
Note - difference between let and const is, let can be re-assigned but const can’t
Class Structure as that of C#:
class Student {
private rollNo: number;
private name: string;
constructor(_rollNo: number, _name: string) {
this.rollNo = _rollNo;
this.name = _name;
}
showDetails() { //public : by default
console.log(this.rollNo + " : " +
this.name);
}
}
let s1 = new Student(1, "Shailendra Chauhan");
s1.showDetails(); //1 : Shailendra Chauhan
let s2 = new Student(2, "kanishk Puri");
s2.showDetails(); //2 : kanishk Puri

4) Important Concepts
a. Databinding
A mechanism for binding data values to HTML elements and turning user activities into
actions.
b. Directives
Change the appearance or behavior of a DOM element.
Component Directives
These are the most common type of directives. They are essentially Angular components,
which include a template and encapsulated logic.
Example
TypeScript
import { Component } from '@angular/core';

@Component({
selector: 'app-hello',
template: `<h1>Hello, {{name}}!</h1>`,
})
export class HelloComponent {
name = 'Angular';
}

Structural directives – used to change the DOM layout by adding and


removing elements
Eg. *ngIf,*ngFor,*ngSwitch
*ngSwitch
<div [ngSwitch]="viewMode">
<div *ngSwitchCase="'map'">Map View</div>
<div *ngSwitchCase="'list'">List View</div>
<div *ngSwitchDefault>Default View</div>
</div>
<button (click)="setViewMode('map')">Map</button>
<button (click)="setViewMode('list')">List</button>
<button (click)="setViewMode('default')">Default</button>

import { Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
viewMode = 'default';

setViewMode(mode: string) {
this.viewMode = mode;
}
}
Attribute Directives –
 ngClass
 ngStyle
 ngModel

 ngClass
The ngClass directive allows you to dynamically add or remove CSS classes to an element.
Example
HTML
<div [ngClass]="{'active': isActive, 'disabled': isDisabled}">
This div can have active and disabled classes.
</div>
<button (click)="toggleActive()">Toggle Active</button>
<button (click)="toggleDisabled()">Toggle Disabled</button>
TypeScript
import { Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
isActive = true;
isDisabled = false;

toggleActive() {
this.isActive = !this.isActive;
}

toggleDisabled() {
this.isDisabled = !this.isDisabled;
}
}
In this example, ngClass dynamically applies the active and disabled classes based on the
values of isActive and isDisabled.
 ngStyle
The ngStyle directive allows you to set inline styles dynamically.
Example
HTML
<div [ngStyle]="{'color': textColor, 'font-size': fontSize}">
This text can change color and size.
</div>
<button (click)="changeColor()">Change Color</button>
<button (click)="changeFontSize()">Change Font Size</button>
TypeScript
import { Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
textColor = 'blue';
fontSize = '16px';

changeColor() {
this.textColor = this.textColor === 'blue' ? 'red' : 'blue';
}

changeFontSize() {
this.fontSize = this.fontSize === '16px' ? '20px' : '16px';
}
}
Here, ngStyle dynamically sets the color and font-size styles based on the values
of textColor and fontSize.
 ngModel
The ngModel directive binds an input, select, or textarea element to a property on the
component.
Pre-requisites - In your app.module.ts file, you need to import FormsModule and add it to
the imports array:
Example
HTML
<input [(ngModel)]="name" placeholder="Enter your name">
<p>Hello, {{name}}!</p>
TypeScript
import { Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
name = '';
}
In this example, ngModel binds the input field to the name property, allowing two-way data
binding.
Two-way data binding means that any changes in the template are reflected in the
component class and vice versa
Custom directive :
in Angular allow you to create reusable components and add behavior to HTML elements
Should be registered in app.module.ts by adding in declarations
HTML:
<div appHoverHighlight >Hover over me!</div>
Custom directive:
import { Directive, ElementRef, HostListener } from '@angular/core';
@Directive({
selector: '[appHoverHighlight]'
})
export class HoverHighlightDirective {
constructor(private el: ElementRef, private renderer: Renderer2) { }

@HostListener('mouseenter') onMouseEnter() {
this.highlight('yellow');
}

@HostListener('mouseleave') onMouseLeave() {
this.highlight(null);
}

private highlight(color: string) {


this.renderer.setStyle(this.el.nativeElement, 'backgroundColor', color);
}
}
 ElementRef: A service that grants direct access to the DOM element.
 Renderer2: A service that allows you to manipulate the DOM in a safe way.
 HostListener: A decorator that listens to events on the host element.
Real time implementations – input validations, tooltip,etc..

c. Pipes or Filters
• Used to transform bound properties before displaying.
• built-In Pipes are : Lowercase ▪ Uppercase ▪ Date ▪ Currency ▪ Json ▪ Decimal
Custom Pipe : Should be registered in app.module.ts by adding in declarations
Code example
Comp.html
<p>The transformed value is: {{ inputValue | custom }}</p>
custom.pipe.ts

Pure Pipe
default pipe, executes when input data changes
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'custom' // Pipe name used within components
pure: true, // Pure pipe (default behavior)
})
export class CustomPipe implements PipeTransform {
transform(value: any, ...args: any[]): any {
// Your transformation logic here
return value.toUpperCase();
}
}

Impure Pipe
Executes on every change detection cycle, even if its input data hasn’t changed.
Real time example – search
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
name: 'filter',
pure: false, // Impure pipe
})
export class FilterPipe implements PipeTransform {
transform(items: any[], searchText: string): any[] {
if (!items) return [];
if (!searchText) return items;
searchText = searchText.toLowerCase();
return items.filter(it => {
return it.name.toLowerCase().includes(searchText);
});
}
}

<input type="text" [(ngModel)]="searchText" placeholder="Search">


<ul>
<li *ngFor="let item of items | filter:searchText">{{ item.name }}</li>
</ul>

In general, you should prefer pure: true for performance reasons unless there's a specific
need for pure: false like change detection cycle.

d. Angular Routing
• It is, Every time when you request a Url, the Angular router navigates to the new
component and renders its template.
 Routing Configuration
• Describe routes in app-routing.module.ts
const routes: Routes = [
{ path: '', component: HomePageInformationComponent },
{ path: 'auth', component: MsalRedirectComponent },
{ path: 'Reports/DailySummaryInput', component: DailyReportComponent }
];
• RouterOutlet is where the router render the component
<app-header></app-header>
<router-outlet></router-outlet>
• RouterLink a link to a route name, router link defined in header component and matches
with defined route in app-routing.module.ts
<li><a class="dropdown-item" (click)="mainheaderdailyreport()"
routerLink="Reports/DailySummaryInput">Daily
Report</a>
</li>

 Route Parameters:
Used to pass data through route paths
Mainly there are following ways :
1. Required Parameters
2. Optional Parameters
3. Query Parameters
Child routes :
const routes: Routes = [
{
path: 'product',
component: ProductComponent,
children: [
{ path: 'detail/:id', component: ProductDetailComponent }
]
}
];
In the above example:
The parent route path is /product.
The child route path is /product/detail/:id.
When the user navigates to /product/detail/123, Angular will render the
ProductDetailComponent.

e. Interceptors
In Angular, an interceptor is a mechanism to intercept and modify HTTP requests or responses in
your application. Interceptors are implemented as services and are part of the Angular HttpClient
module.

Usage - for http requests in adding token

ng generate service auth-interceptor

auth-interceptor

import { Injectable } from '@angular/core';


import {
HttpInterceptor,
HttpRequest,
HttpHandler,
HttpEvent
} from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable()
export class AuthInterceptorService implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Add an Authorization header to every request
const token = 'your-auth-token'; // Replace with your token logic

if (token) {
request = request.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
}

// Pass the modified request to the next handler


return next.handle(request);
}
}

Register in app.module.ts under providers


providers: [
{ provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
multi: true, // Allows multiple interceptors
},
]

Syntax to write interceptor


import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from
'@angular/common/http';
import { Observable } from 'rxjs';

@Injectable()
export class MyInterceptorService implements HttpInterceptor {

intercept(req: HttpRequest<any>, next: HttpHandler):


Observable<HttpEvent<any>> {
// Modify the request (e.g., add headers)
const modifiedReq = req.clone({
setHeaders: {
'Custom-Header': 'HeaderValue'
}
});

// Forward the modified request to the next handler


return next.handle(modifiedReq);
}
}

f. Guards

Guards in Angular are used to control a route. They are essentially services that implement one or
more guard interfaces to decide whether a route can be activated, deactivated, loaded, or unloaded.

5) Nested Components
@Input Decorator – parent to child communication
@Output Decorator – child to parent communication

@Input Decorator
Child component
import { Component, Input } from '@angular/core';

@Component({
selector: 'app-child',
template: `<p>{{ childMessage }}</p>`
})
export class ChildComponent {
@Input() childMessage: string;
}
Parent Component:
import { Component } from '@angular/core';

@Component({
selector: 'app-parent',
template: `<app-child [childMessage]="parentMessage"></app-child>`
})
export class ParentComponent {
parentMessage = 'Hello from Parent!';
}

@Output Decorator
Child component
import { Component, Output, EventEmitter } from '@angular/core';

@Component({
selector: 'app-child',
template: `<button (click)="sendMessage()">Send Message</button>`
})
export class ChildComponent {
@Output() messageEvent = new EventEmitter<string>();

sendMessage() {
this.messageEvent.emit('Hello from Child!');
}
}

Parent Component:

import { Component } from '@angular/core';


@Component({
selector: 'app-parent',
template: `<app-child (messageEvent)="receiveMessage($event)"></app-child>
<p>{{ message }}</p>`
})
export class ParentComponent {
message: string;

receiveMessage($event: string) {
this.message = $event;
}
}

6) Content Projection

Content projection examples - Cards, tabs, navbars, modals and dialogs


<ng-content> directive is used for content projection
Child Component:
import { Component } from '@angular/core';

@Component({
selector: 'app-child',
template: `
<div class="header">
<ng-content select="[header]"></ng-content>
</div>
<div class="body">
<ng-content select="[body]"></ng-content>
</div>
<div class="footer">
<ng-content select="[footer]"></ng-content>
</div>
`
})
export class ChildComponent {}
Parent Component:
attribute selectors
import { Component } from '@angular/core';

@Component({
selector: 'app-parent',
template: `
<app-child>
<h1 header>Header Content</h1>
<p body>Body Content</p>
<footer footer>Footer Content</footer>
</app-child>
`
})
export class ParentComponent {}
7) @ViewChild
The @ViewChild decorator in Angular is used to access a child component, directive, or DOM
element from a parent component class.
Ex 1:
Child Component:
import { Component } from '@angular/core';

@Component({
selector: 'app-child',
template: `<p>Hello from Child Component!</p>`
})
export class ChildComponent {
sayHello() {
console.log('Hello from Child Component!');
}
}

Parent Component:
import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ChildComponent } from './child.component';
@Component({
selector: 'app-parent',
template: `<app-child></app-child>
<button (click)="callChildMethod()">Call Child Method</button>`
})
export class ParentComponent implements AfterViewInit {
@ViewChild(ChildComponent) childComponent!: ChildComponent;

ngAfterViewInit() {
// Access child component's method after view initialization
// lifecycle hook ensures that the child component is fully initialized before accessing its
methods.
this.childComponent.sayHello();
}
callChildMethod() {
this.childComponent.sayHello();
}
}
Ex 2:
You can also use @ViewChild to access a DOM element using a template reference variable:
HTML
<input #inputElement type="text" placeholder="Enter text">
<button (click)="logInputValue()">Log Input Value</button>

Component:
import { Component, ViewChild, ElementRef } from '@angular/core';
@Component({
selector: 'app-example',
templateUrl: './example.component.html'
})
export class ExampleComponent {
@ViewChild('inputElement') inputElement!: ElementRef;

logInputValue() {
console.log(this.inputElement.nativeElement.value);
}
}
Difference between pipes and directives
 Pipes: Transform data in templates, used with the pipe (|) symbol, stateless.
 Directives: Add behavior to DOM elements, used as attributes, can be stateful.

8) Angular Lifecycle Hooks


1. ngOnChanges: Called when an input property changes.
2. ngOnInit: Called once the component is initialized.
3. ngDoCheck: Called during every change detection run.
4. ngAfterContentInit: Called after content (ng-content) has been projected into the
view.
5. ngAfterContentChecked: Called after every check of projected content.
6. ngAfterViewInit: Called after the component’s view (and child views) has been
initialized.
7. ngAfterViewChecked: Called after every check of the component’s view (and child
views).
8. ngOnDestroy: Called just before the component is destroyed.
Explanation -
1. constructor()
constructor() {
console.log('Constructor: Component instance created');
}
Explanation: The constructor() is the first method called when the
component is created. It's used to set up any initial values and inject
dependencies.
When is it called?: As soon as the component is instantiated, but before
any input properties are set or the component view is rendered.
Logs: "Constructor: Component instance created"
2. ngOnChanges()
ngOnChanges() {
console.log('ngOnChanges: Called when any input property changes');
}
Explanation: This hook is triggered whenever an @Input() property
changes, either from the parent component or from inside the component.
In this case, name is an input property, so it will be called whenever name
changes.
When is it called?: This hook is called before ngOnInit() and whenever
input properties change, whether at initialization or during updates.
Logs: "ngOnChanges: Called when any input property changes"
3. ngOnInit()
ngOnInit() {
console.log('ngOnInit: Component initialized (called once)');
}
Explanation: ngOnInit() is called once after the component has been
initialized and Angular has set up the input properties.
When is it called?: This hook is called after the first ngOnChanges() when
the component has fully initialized. It’s ideal for setup logic such as data
fetching or initialization tasks.
Logs: "ngOnInit: Component initialized (called once)"
4. ngDoCheck()
ngDoCheck() {
console.log('ngDoCheck: Custom change detection logic executed');
}
Explanation: ngDoCheck() is called during every change detection cycle.
This allows you to implement custom change detection logic.
When is it called?: This hook runs every time Angular checks for changes
in the component, even if the component's input properties haven't
changed. It is triggered after ngOnChanges and ngOnInit, but before
ngAfterContentInit and ngAfterViewInit.
Logs: "ngDoCheck: Custom change detection logic executed"
5. ngAfterContentInit()
ngAfterContentInit() {
console.log('ngAfterContentInit: Called after content projection (ng-
content) initialized');
}
Explanation: ngAfterContentInit() is called once after the component's
content has been projected (if you are using <ng-content> in the
template).
When is it called?: This hook is called after Angular has finished initializing
the content projected into the component.
Logs: "ngAfterContentInit: Called after content projection (ng-content)
initialized"
6. ngAfterContentChecked()
ngAfterContentChecked() {
console.log('ngAfterContentChecked: Called after every content
projection check');
}
Explanation: ngAfterContentChecked() is called after every change
detection cycle that checks the projected content.
When is it called?: This is called after ngAfterContentInit() and after every
subsequent check of the projected content, typically after changes in the
component's projected content (using <ng-content>).
Logs: "ngAfterContentChecked: Called after every content projection
check"
7. ngAfterViewInit()
ngAfterViewInit() {
console.log('ngAfterViewInit: Component view initialized (and child views
if any)');
}
Explanation: ngAfterViewInit() is called after Angular initializes the
component's view (including child views if present).
When is it called?: It’s called after ngAfterContentInit() and after Angular
has finished initializing the view of the component and all its child views.
This is ideal for performing any operations that depend on the
component's view being fully initialized.
Logs: "ngAfterViewInit: Component view initialized (and child views if
any)"
8. ngAfterViewChecked()
ngAfterViewChecked() {
console.log('ngAfterViewChecked: Called after every view check
(including child views)');
}
Explanation: ngAfterViewChecked() is called after every change detection
cycle that checks the component's view and child views.
When is it called?: This hook is triggered after ngAfterViewInit() and every
time Angular checks for changes in the component's view, including
changes to child views.
Logs: "ngAfterViewChecked: Called after every view check (including child
views) changes"
9. ngOnDestroy()
ngOnDestroy() {
console.log('ngOnDestroy: Component about to be destroyed');
}
Explanation: ngOnDestroy() is called just before Angular destroys the
component. It’s typically used for cleanup tasks such as unsubscribing
from observables, clearing timeouts, or removing event listeners.
When is it called?: This hook is invoked when the component is about to
be destroyed. This can happen when the component is removed from the
view or when navigating away from the page.

9) State Management in Angular using services


ng generate service my-service
Real-Time Example: Sharing Data Between Unrelated Components
Step 1: Create the Message Service
// message.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable({
providedIn: 'root',
})
export class MessageService {
private messageSubject = new BehaviorSubject<string>(''); // Default message is
empty
message$ = this.messageSubject.asObservable(); // Observable for message
updates

sendMessage(message: string) {
this.messageSubject.next(message); // Emit the new message
}

clearMessage() {
this.messageSubject.next(''); // Clear the message
}
}

Step 2: Create the Message Sender Component

// message-sender.component.ts
import { Component } from '@angular/core';
import { MessageService } from './message.service';

@Component({
selector: 'app-message-sender',
template: `
<h2>Message Sender</h2>
<input [(ngModel)]="message" placeholder="Type a message" />
<button (click)="sendMessage()">Send Message</button>
`,
})
export class MessageSenderComponent {
message: string = ''; // Message input

constructor(private messageService: MessageService) {}

sendMessage() {
this.messageService.sendMessage(this.message); // Send the message via the
service
this.message = ''; // Clear the input after sending
}
}

Step 3: Create the Message Receiver Component

// message-receiver.component.ts
import { Component } from '@angular/core';
import { MessageService } from './message.service';

@Component({
selector: 'app-message-receiver',
template: `
<h2>Message Receiver</h2>
<div *ngIf="message">Received Message: {{ message }}</div>
<div *ngIf="!message">No messages received yet.</div>
`,
})
export class MessageReceiverComponent {
message: string = ''; // Message received

constructor(private messageService: MessageService) {


// Subscribe to message updates
this.messageService.message$.subscribe((message) => {
this.message = message; // Update the received message
});
}
}

Step 4: Use the Components in the Application


<app-message-sender></app-message-sender>
<app-message-receiver></app-message-receiver>
When components are un-related, we can use services to make data communication
Loader is another such example which we use in our application

10) Session storage vs local storage


Local Storage
 Persistence: Data persists even after the browser is closed and reopened.
 Scope: Data is stored per domain and is accessible across all tabs and
windows.
 Use Case: Suitable for storing data that needs to be available across
sessions, like user preferences or settings.
// Save data to local storage
localStorage.setItem('username', 'JohnDoe');

// Retrieve data from local storage


const username = localStorage.getItem('username');
console.log(username); // Output: JohnDoe

// Remove data from local storage


localStorage.removeItem('username');

// Clear all data from local storage


localStorage.clear();
Session Storage
 Persistence: Data is cleared when the page session ends (i.e., when the
browser tab is closed).
 Scope: Data is specific to a single tab and is not shared across tabs or
windows.

// Save data to session storage


sessionStorage.setItem('sessionId', '123456');

// Retrieve data from session storage


const sessionId = sessionStorage.getItem('sessionId');
console.log(sessionId); // Output: 123456

// Remove data from session storage


sessionStorage.removeItem('sessionId');

// Clear all data from session storage


sessionStorage.clear();

11) Performance optimization techniques

10.1 What is Change Detection in Angular?


Change detection in Angular is a mechanism that tracks changes in application data
and updates the DOM when necessary. It keeps the application's data model and
view in sync. When data changes, Angular knows it needs to update parts of the
DOM to reflect the latest data.

What is Zone.js?

Zone.js is a JavaScript library that Angular uses to "listen" to asynchronous


operations, such as:
 User events (e.g., button clicks, typing)
 HTTP requests
 Timers (e.g., setTimeout)

Change Detection and Zone.js in Action


// counter.component.ts
import { Component, NgZone } from '@angular/core';

@Component({
selector: 'app-counter',
template: `
<h1>Counter: {{ counter }}</h1>
<button (click)="resetCounter()">Reset Counter</button>
`,
})
export class CounterComponent {
counter = 0;

constructor(private ngZone: NgZone) {


// Start an interval to increment the counter every second
this.ngZone.runOutsideAngular(() => { //this avoids zone.js hits
setInterval(() => {
this.ngZone.run(() => { // this explicitly hits zone.js
this.counter++;
});
}, 1000);
});
}

resetCounter() {
this.counter = 0;
}
}
1. OnPush Change Detection Strategy (between the components)

Step 1: Product Card Component with OnPush


import { Component, ChangeDetectionStrategy, Input, Output,
EventEmitter } from '@angular/core';

@Component({
selector: 'app-product-card',
template: `
<div>
<h3>{{ product.name }}</h3>
<p>Price: {{ product.price }}</p>
<button (click)="addToCart()">Add to Cart</button>
<button (click)="updatePrice()">Update Price</button>
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush // Activates OnPush
strategy
})
export class ProductCardComponent {
@Input() product: { name: string; price: number }; // Receives product data
from the parent
@Output() priceUpdate = new EventEmitter<void>(); // Emits an event
when the price is updated

addToCart() {
console.log(`${this.product.name} added to cart!`); // Logs to console
when button clicked
}

updatePrice() {
this.priceUpdate.emit(); // Triggers the update price event
}
}

Step 2: Handle Price Update in the Parent Component

import { Component } from '@angular/core';

@Component({
selector: 'app-root',
template: `
<app-product-card
*ngFor="let item of products"
[product]="item"
(priceUpdate)="updatePrice(item)">
</app-product-card>
`,
})
export class AppComponent {
products = [
{ name: 'Laptop', price: 1000 },
{ name: 'Phone', price: 500 }
];

updatePrice(product) {
// Update the product price by increasing it by a fixed amount, e.g., 200
product.price += 200;
this.products = [...this.products]; // Trigger change detection for OnPush
}
}

Result
With this setup:
Each ProductCardComponent has its own "Update Price" button.
Clicking "Update Price" updates the price only for that specific product card without
re-rendering the others.
2. OnPush Change Detection Strategy and trackby
Above can be achieved by using single component only, by using OnPush
Change Detection Strategy and trackby

Step 1: Create a Product List Component with OnPush


In this example, the component displays multiple products and allows you to
update each product’s price individually.

import { Component, ChangeDetectionStrategy } from '@angular/core';

@Component({
selector: 'app-product-list',
template: `
<div *ngFor="let product of products; trackBy: trackByProductId">
<h3>{{ product.name }}</h3>
<p>Price: {{ product.price }}</p>
<button (click)="addToCart(product)">Add to Cart</button>
<button (click)="updatePrice(product)">Update Price</button>
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush // Optimizes performance
})
export class ProductListComponent {
products = [
{ id: 1, name: 'Laptop', price: 1000 },
{ id: 2, name: 'Phone', price: 500 }
];

addToCart(product) {
console.log(`${product.name} added to cart!`);
}

updatePrice(product) {
// Updates the price for the selected product
product.price += 200;
this.products = [...this.products]; // Triggers change detection for OnPush
}

trackByProductId(index: number, product: any): number {


return product.id; // Uniquely identify each product by its ID
}
}
10.2 Lazy Loading

Lazy loading is a technique used in web development, including Angular


applications, where certain parts (or modules) of an application are loaded
only when they are needed, instead of loading everything at the start.

Setting Up Lazy Loading in Angular

Step 1: Create a New Angular Application


ng new lazy-loading-example
cd lazy-loading-example
ng serve

Step 2: Generate Modules and Components


Generate the Home and Feature modules along with their components:

ng generate module home --routing


ng generate component home/home
ng generate module feature --routing
ng generate component feature/feature

Step 3: Configure Routes


src/app/app-routing.module.ts: Update the app's main routing module to load
the HomeModule eagerly and the FeatureModule lazily.

import { NgModule } from '@angular/core';


import { RouterModule, Routes } from '@angular/router';

const routes: Routes = [


{
path: '',
loadChildren: () =>
import('./home/home.module').then((m) => m.HomeModule),
},
{
path: 'feature',
loadChildren: () =>
import('./feature/feature.module').then((m) => m.FeatureModule),
},
];

@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}

Step 4: Configure Home Module


src/app/home/home-routing.module.ts: Define the routing for the
HomeModule.

import { NgModule } from '@angular/core';


import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home.component';

const routes: Routes = [{ path: '', component: HomeComponent }];

@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class HomeRoutingModule {}

src/app/home/home.component.ts: Create a simple Home component.


import { Component } from '@angular/core';

@Component({
selector: 'app-home',
template: `<h1>Home Page</h1>
<a routerLink="/feature">Go to Feature Page</a>`,
})
export class HomeComponent {}

repeat the same for feature module

In this way performance improves and memory consumption will be less.

Project Structure
Here’s a suggested structure for the E-Commerce application:

e-commerce-app/

├── src/
│ ├── app/
│ │ ├── cart/
│ │ │ ├── cart-routing.module.ts
│ │ │ ├── cart.module.ts
│ │ │ ├── cart.component.ts
│ │ │ └── cart.service.ts
│ │ │
│ │ ├── order/
│ │ │ ├── order-routing.module.ts
│ │ │ ├── order.module.ts
│ │ │ ├── order.component.ts
│ │ │ └── order.service.ts
│ │ │
│ │ ├── product/
│ │ │ ├── product-routing.module.ts
│ │ │ ├── product.module.ts
│ │ │ ├── product.component.ts
│ │ │ └── product.service.ts
│ │ │
│ │ ├── user/
│ │ │ ├── user-routing.module.ts
│ │ │ ├── user.module.ts
│ │ │ ├── user.component.ts
│ │ │ └── user.service.ts
│ │ │
│ │ ├── app-routing.module.ts
│ │ ├── app.module.ts
│ │ └── app.component.ts
│ │
│ ├── assets/
│ └── index.html

└── angular.json

10.3 Avoid Unnecessary HTTP Calls with Caching

To avoid unnecessary HTTP calls in Angular, caching can store previously


fetched data, allowing it to be reused without making repeated requests to
the server. Here’s a simple example:

See code in Angularnetcore project

Real time scenario - user related information like user id, static data which
won’t changes at DB end

But, after refresh cache gets cleared and data retrieves from server again

Cache Lifetime:
 Data persists in the cache for the entire lifespan of the application's
session in the browser (i.e., until the user refreshes or closes the
browser tab, we have to explicitly clear
This is only for small datasets, avoid storing large datasets as it leads to
performance issue.

Hence, Using localStorage or sessionStorage allows caching to persist across


page refreshes, making the application feel faster, especially for data that
doesn’t change frequently.

This is the adavntage of localStorage or sessionStorage over cache


12) Template-Driven Forms vs model driven
form(reactive form)

Template-Driven Forms
This form is simple to use and is typically recommended for straightforward
forms that don't require extensive custom validations or dynamic fields.

Key Concepts of Template-driven Forms


ngModel Directive: Used for two-way data binding between the form input
elements and the component’s model.
ngForm Directive: Angular automatically attaches ngForm to <form> tags to
manage the form’s state and validation.
Template Validation: You can specify validation rules directly in the HTML
using attributes like required, minlength, and pattern.
Form State: Angular provides access to the form's state, including whether it's
valid or invalid, touched or untouched, and dirty or pristine.

Configuration
App.module.ts
import { FormsModule } from '@angular/forms'; // Import FormsModule
imports: [ BrowserModule, FormsModule // Add FormsModule to imports ],
-------------------------------------------------------------------------

<form #registrationForm="ngForm"
(ngSubmit)="onSubmit(registrationForm)">
<div>
<label for="username">Username:</label>
<input
type="text"
id="username" <!-- 'id' for label association -->
name="username" <!-- 'name' for Angular to track the form control
-->
ngModel <!-- enables two-way data binding -->
required
minlength="3"
#username="ngModel" <!-- local template reference for validation -->
[class.modified]="username.dirty"
/>
<div *ngIf="username.invalid && username.touched">
<small *ngIf="username.errors?.required">Username is required.</small>
<small *ngIf="username.errors?.minlength">Username must be at least 3
characters.</small>
</div>
</div>

<div>
<label for="email">Email:</label>
<input
type="email"
id="email" <!-- 'id' for label association -->
name="email" <!-- 'name' for Angular to track the form control --
>
ngModel
required
email
#email="ngModel"
/>
<div *ngIf="email.invalid && email.touched">
<small *ngIf="email.errors?.required">Email is required.</small>
<small *ngIf="email.errors?.email">Please enter a valid email
address.</small>
</div>
</div>

<div>
<label for="password">Password:</label>
<input
type="password"
id="password" <!-- 'id' for label association -->
name="password" <!-- 'name' for Angular to track the form control
-->
ngModel
required
minlength="6"
#password="ngModel"
/>
<div *ngIf="password.invalid && password.touched">
<small *ngIf="password.errors?.required">Password is required.</small>
<small *ngIf="password.errors?.minlength">Password must be at least 6
characters.</small>
</div>
</div>

<button type="submit" [disabled]="


registrationForm.pristine">Register</button>
</form>
-------------------------------------------------------------------------
import { Component } from '@angular/core';

@Component({
selector: 'app-registration',
templateUrl: './registration.component.html',
})
export class RegistrationComponent {
onSubmit(form: any) {
if (form.valid) {
console.log('Form Submitted!', form.value);
}
}
}
-------------------------------------------------------------------------
.modified {
border: 1px solid orange; /* Highlights modified fields */
}

Validations and Control state in angular template driven forms


 Control States: valid, invalid, touched, untouched, dirty, pristine
 Validators: required, minlength, maxlength, pattern, email
Note -
 Prestine use - Disable submit button if no changes have been made
(when the form is pristine).
 dirty use - Visually highlight unsaved fields to remind users of
modified data (dirty state).

Reactive (Model-Driven) Forms


Angular Reactive Forms provide a model-driven approach to handling form
inputs and validations in Angular applications. Reactive Forms allow you to
manage the state and validation of form inputs in a more predictable way by
using a reactive programming style.

Configuration
App.module.ts

import { ReactiveFormsModule } from '@angular/forms'; // Import


ReactiveFormsModule
imports: [ BrowserModule, ReactiveFormsModule // Add it to imports ],

-------------------------------------------------------------------------

<form [formGroup]="myForm" (ngSubmit)="onSubmit()">


<label for="name">Name:</label>
<input id="name" formControlName="name">
<div *ngIf="myForm.get('name').invalid && (myForm.get('name').touched ||
myForm.get('name').dirty)">
<small *ngIf="myForm.get('name').errors?.required">Name is
required.</small>
</div>

<label for="email">Email:</label>
<input id="email" formControlName="email">
<div *ngIf="myForm.get('email').invalid && (myForm.get('email').touched ||
myForm.get('email').dirty)">
<small *ngIf="myForm.get('email').errors?.required">Email is
required.</small>
<small *ngIf="myForm.get('email').errors?.email">Enter a valid
email.</small>
</div>

<button type="submit" [disabled]="myForm.invalid">Submit</button>


</form>

-------------------------------------------------------------------------
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
myForm: FormGroup;

constructor(private fb: FormBuilder) {


// Initialize the form using FormBuilder
this.myForm = this.fb.group({
name: ['', Validators.required], // Name field with required validator
email: ['', [Validators.required, Validators.email]], // Email field with
validators
});
}

ngOnInit(): void {}

onSubmit() {
if (this.myForm.valid) {
console.log('Form Submitted!', this.myForm.value);
}
}
}

Key terms
 FormGroup: A container for managing multiple form controls
together.
 formControlName: A directive to link input fields in your HTML to
specific controls in a FormGroup.
 FormBuilder: A service to help create form controls and groups in a
simpler and cleaner way.
-------------------------------------------------------------------------
Validations and Control state in angular reactive forms

 Validators
import { FormGroup, FormBuilder, Validators } from '@angular/forms';

constructor(private fb: FormBuilder) {


this.myForm = this.fb.group({
name: ['', Validators.required], // Name is required
email: ['', [Validators.required, Validators.email]], // Email is required and
must be valid
password: ['', [Validators.required, Validators.minLength(6)]], // Password is
required with a minimum length of 6
});
}

 Control States: valid, invalid, touched, untouched, dirty, pristine


Ex:
<!-- Show message if the field is pristine -->
<div *ngIf="myForm.get('name').pristine"> <small style="color:
gray;">You haven't changed the name field yet.</small> </div>
<!-- Submit button is disabled if the form is pristine --> <button
type="submit" [disabled]="myForm.pristine">Submit</button>

Summary
 Template-Driven Forms: Simpler, less boilerplate, suitable for small forms.
 Reactive Forms: More control, better for complex forms, explicit validation.

13) Authentication and types

Authentication is the process of verifying who a user is.

1. Token-Based Authentication: Uses a token (like JWT) to verify users on each


request.
2. Cookie-Based Authentication: Relies on a server-set cookie to identify users
automatically.
3. OAuth2/OpenID Connect: Enables Single Sign-On (SSO) by redirecting users
to a trusted provider for login.
4. Basic Authentication: Sends username and password with each request (less
secure).
5. Two-Factor Authentication (2FA): Requires an additional code along with
password for added security.

14) SSO Authentication

Step-by-Step Guide to Implementing SSO Authentication with Azure AD in Angular

1. Register Your Application in Azure AD


 Go to the Azure Portal and sign in.

 Navigate to Azure Active Directory > App registrations > New registration.

 Fill in the following:

o Name: Enter a name for your app (e.g., "My Angular App").

o Supported account types: Choose which accounts can use the application (e.g.,
"Accounts in this organizational directory only").
o Redirect URI: Set the redirect URI to match your Angular app's URL with /auth-
callback (e.g., http://localhost:4200/auth-callback).

 Click Register to create the application.

 After registration, note down the Application (client) ID and Directory (tenant) ID from the
app overview page.

2. Configure API Permissions


 In your registered application, go to API permissions > Add a permission.

 Choose Microsoft Graph and select the permissions needed for your application (e.g.,
User.Read for basic profile access).

 Click Add permissions.

 If necessary, Grant admin consent for your organization.

3. Install the MSAL Library in Angular


 Open your Angular project in a terminal.

 Install the @azure/msal-angular and @azure/msal-browser libraries:

npm install @azure/msal-angular @azure/msal-browser

4. Create auth-config.ts for Azure AD Configuration


In your Angular project, create a file named auth-config.ts in the src directory. This file will store your
Azure AD configuration.

typescript

// src/auth-config.ts

export const msalConfig = {

auth: {

clientId: 'your-client-id', // Application (client) ID from Azure AD

authority: 'https://login.microsoftonline.com/your-tenant-id', // Directory (tenant) ID

redirectUri: 'http://localhost:4200/auth-callback' // Redirect URI

};

export const loginRequest = {


scopes: ['User.Read'] // Permissions requested during login

};

Replace your-client-id and your-tenant-id with your actual Application (client) ID and Directory
(tenant) ID from Azure AD.

5. Update app.module.ts to Use the Configuration


In app.module.ts, import msalConfig and loginRequest from auth-config.ts and configure MSAL.

typescript

// src/app/app.module.ts

import { NgModule } from '@angular/core';

import { BrowserModule } from '@angular/platform-browser';

import { MsalModule, MsalService, MsalGuard, MsalRedirectComponent } from '@azure/msal-


angular';

import { PublicClientApplication, InteractionType } from '@azure/msal-browser';

import { msalConfig, loginRequest } from '../auth-config'; // Import configuration

@NgModule({

declarations: [AppComponent],

imports: [

BrowserModule,

MsalModule.forRoot(

new PublicClientApplication(msalConfig), // Use imported config

interactionType: InteractionType.Redirect, // Authentication flow

authRequest: loginRequest, // Scopes defined in config

),

],

providers: [MsalService, MsalGuard],

bootstrap: [AppComponent, MsalRedirectComponent]

})
export class AppModule {}

6. Configure Routing with Authentication Guard


In app-routing.module.ts, add MsalGuard to the protected routes and set up the callback route.

typescript

// src/app/app-routing.module.ts

import { NgModule } from '@angular/core';

import { RouterModule, Routes } from '@angular/router';

import { MsalGuard } from '@azure/msal-angular';

import { MsalRedirectComponent } from '@azure/msal-angular';

const routes: Routes = [

{ path: 'protected', component: ProtectedComponent, canActivate: [MsalGuard] },

{ path: 'public', component: PublicComponent },

{ path: 'auth-callback', component: MsalRedirectComponent }, // Redirect callback

{ path: '', redirectTo: '/public', pathMatch: 'full' },

];

@NgModule({

imports: [RouterModule.forRoot(routes)],

exports: [RouterModule]

})

export class AppRoutingModule {}

7. Implement Login and Logout in app.component.ts


In your app.component.ts, inject the MsalService to handle login and logout actions.

typescript

// src/app/app.component.ts

import { Component, OnInit } from '@angular/core';


import { MsalService } from '@azure/msal-angular';

@Component({

selector: 'app-root',

templateUrl: './app.component.html'

})

export class AppComponent implements OnInit {

isLoggedIn = false;

constructor(private authService: MsalService) {}

ngOnInit() {

this.authService.instance.handleRedirectPromise().then((response) => {

this.isLoggedIn = this.authService.instance.getAllAccounts().length > 0;

});

login() {

this.authService.loginRedirect();

logout() {

this.authService.logoutRedirect({ postLogoutRedirectUri: 'http://localhost:4200' });

Overall flow – refer complete code of authentication in another file


Here's a condensed flow of authentication in your Angular application's HeaderComponent:

1. Initialization: The component initializes and subscribes to router events to check the user's
authentication status.

2. Check Authentication: The checkUserAuthentication() method initializes MSAL and checks if


there is an active account. If not, it retrieves any available accounts.
3. Set Authentication Status: The setAuthenticationStatus() method updates the
authentication state based on the active account and stores user information in local storage.

4. Handle Login Events: The component subscribes to MSAL login success events. Upon
successful login, it sets the active account and updates the authentication status and user
info.

5. Load Menu and Roles: The LoadMenuSubMenus() method fetches the application menu
items, while GetUserRoleMembers() retrieves the user’s roles based on their ID.

6. Login and Logout: The component defines methods to initiate login and logout processes
using MSAL.

7. User Information: The loadUserFromLocalStorage() method retrieves the user's ID and name
from local storage to update the UI.

Note – this authentication gets active account from MSAL instance

15) Authorization using role guard and auth


service– Screen level Accesses

Step 1: Add Roles to User Authentication Data

Step 2: Create an AuthService to Get User Roles, checks has role, checks has screen
access

Step 3: Create a RoleGuard to Protect Routes

Step 4: Configure Routes with the RoleGuard

Flow Summary

1. Login: User logs in, and roles are stored in AuthService.

2. Route Access Attempt: User tries to access a route (e.g., /admin).

3. Guard Execution: Angular triggers the RoleGuard for the route.

4. Role Check: RoleGuard checks if the user’s roles match the required roles.

o If true: Route access is allowed.

o If false: User is redirected to an unauthorized page.

For more details refer Authorization document


16) Dependeny Injection in Angular

Dependency Injection (DI) is a design pattern in Angular that provides a way to supply a class with its
dependencies without the class having to create them itself.

Keywords - Service, Injector, provider

Example: DI in Angular
Let's create a simple service to understand how DI works in Angular.
1. Create a Service
Use the Angular CLI to generate a service:
ng generate service greeting

greeting.service.ts:
import { Injectable } from '@angular/core';

the provider for GreetingService is implicitly defined in their @Injectable decorators:


@Injectable({
providedIn: 'root', // Makes the service available throughout the app
})
export class GreetingService {
getGreeting(): string {
return 'Hello, welcome to Dependency Injection in Angular!';
}
}

2. Inject the Service into a Component


Use the service in a component.

app.component.ts:
import { Component } from '@angular/core';
import { GreetingService } from './greeting.service';

@Component({
selector: 'app-root',
template: `<h1>{{ message }}</h1>`,
})
export class AppComponent {
message: string = '';

constructor(private greetingService: GreetingService) {


// Dependency is injected via the constructor
this.message = this.greetingService.getGreeting();
}
}
17.1 Providers and types

providers are used to inject dependencies into components, services, or other parts of the
application

Class Providers - above is the best example of class providers


Value Providers –
A Value Provider in Angular is a way to provide a fixed value (like a constant or configuration data) to
be used across your application

1. API Endpoints as real time implementaion


Applications often communicate with multiple APIs (e.g., User API, Product API). A value provider can
centralize the base URLs or endpoints.

App.module.ts

@NgModule({
providers: [
{ provide: 'BASE_API_URL', useValue: 'https://api.myapp.com' },
],
})
export class AppModule {}

Usage in a Service:
@Injectable({
providedIn: 'root',
})
export class DataService {
constructor(@Inject('BASE_API_URL') private baseUrl: string, private http: HttpClient) {}

getUsers() {
return this.http.get(`${this.baseUrl}/users`);
}
}

Factory Provider

A Factory Provider in Angular is used when you need to dynamically create or calculate a value based
on logic and can be used across application

1. API Endpoints as real time implementaion

Environment files

export const environment = {


production: false, // Set to false for development environment
apiUrl: 'https://dev-api.example.com', // Dev API URL
};
export const environment = {
production: true, // Set to true for production environment
apiUrl: 'https://prod-api.example.com', // Prod API URL
};

Angular.json file

"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
]

api-factory.ts

import { environment } from '../environments/environment';

export function apiEndpointFactory(): string {


return environment.apiUrl; // Return the API URL based on the environment
}

app.module.ts

import { NgModule } from '@angular/core';


import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { apiEndpointFactory } from './api-factory';

@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [
{ provide: 'API_URL', useFactory: apiEndpointFactory }, // Register the factory provider
],
bootstrap: [AppComponent],
})
export class AppModule {}

data.service.ts

import { Injectable, Inject } from '@angular/core';


import { HttpClient } from '@angular/common/http';

@Injectable({
providedIn: 'root',
})
export class DataService {
constructor(@Inject('API_URL') private apiUrl: string, private http: HttpClient) {}

getUsers() {
return this.http.get(`${this.apiUrl}/users`); // Use the dynamically injected API URL
}
}

This approach ensures that your application uses the correct API endpoint based on the build
environment, keeping things flexible and maintainable

Existing Providers

17) How to integrate Kendo telerik UI to


angular
Install packages using npm commands

npm install --save @progress/kendo-angular-ui

npm install --save @progress/kendo-theme-default

npm install --save @progress/kendo-angular-license

Configure main.ts file

import { enableProdMode } from '@angular/core';


import { setIntlService } from '@progress/kendo-angular-intl';
import { KendoAngularLicense } from '@progress/kendo-angular-license';

// Set your Kendo UI license key


KendoAngularLicense.setLicenseKey('your-license-key-here');

// Enable production mode for optimized performance (if required)


enableProdMode();

Import Kendo UI Modules in Your Angular Application


import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { GridModule } from '@progress/kendo-angular-grid'; // Example: Import Kendo Grid
Module

@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
GridModule // Add the Kendo Grid module to your app
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

18) Make api calls from angular service

import { Injectable } from '@angular/core';


import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
providedIn: 'root'
})
export class ApiService {

private baseUrl: string = 'https://your-api-base-url.com/api'; // Replace with your


API base URL

constructor(private http: HttpClient) {}

// GET: Fetch all users


public getAllUsers(): Observable<any> {
return this.http.get(`${this.baseUrl}/users`);
}

// GET: Fetch user by ID


public getUserById(id: number): Observable<any> {
return this.http.get(`${this.baseUrl}/users/${id}`);
}

// POST: Create a new user


public createUser(data: any): Observable<any> {
return this.http.post(`${this.baseUrl}/users`, data);
}

// PUT: Update a user by ID


public updateUser(id: number, data: any): Observable<any> {
return this.http.put(`${this.baseUrl}/users/${id}`, data);
}

// DELETE: Delete a user by ID


public deleteUser(id: number): Observable<any> {
return this.http.delete(`${this.baseUrl}/users/${id}`);
}
}

19) forkjoin -How to make multiple api calls


from an angular component
Using forkjoin

forkJoin is an operator that runs multiple observables in parallel.

import { Component, OnInit } from '@angular/core';

import { ApiService } from './api.service'; // Import the ApiService

import { forkJoin } from 'rxjs';

@Component({

selector: 'app-root',

templateUrl: './app.component.html',

styleUrls: ['./app.component.css']

})

export class AppComponent implements OnInit {

api1Data: any;

api2Data: any;

loading: boolean = true;

error: string = '';

constructor(private apiService: ApiService) {}

ngOnInit(): void {

// Make multiple API calls using forkJoin

this.makeApiCalls();
}

makeApiCalls(): void {

forkJoin([

this.apiService.getPosts(), // Call getPosts from ApiService

this.apiService.getUsers() // Call getUsers from ApiService

]).subscribe({

next: ([api1Response, api2Response]) => {

this.api1Data = api1Response;

this.api2Data = api2Response;

this.loading = false;

},

error: (err) => {

this.error = 'An error occurred while fetching data';

this.loading = false;

});

20) Rxjs
It provides a way to work with asynchronous data streams and enables a more declarative approach
to handle events, AJAX requests, and data transformations

21.1) Observable, Observer, Subscriber


Observable - An Observable is part of RxJS (Reactive Extensions for JavaScript) and represents a
stream of data that can emit multiple values over time

Observer - An Observer is an object or a function that receives and handles/reacts to data emitted
by an Observable.

Subscriber – listener which listens to values emitted by observable

Analogy –

Observable – Radio station

Observer - DJ
Subscriber – we listeners

Real time example of observable and observer - sending bulk data in batches

import { Injectable } from '@angular/core';


import { Observable, Observer, from } from 'rxjs';
import { mergeMap, delay, toArray } from 'rxjs/operators';
import { HttpClient } from '@angular/common/http';

// Import necessary Angular and RxJS modules for creating a service and handling HTTP requests and
Observables.

@Injectable({
providedIn: 'root',
})
export class BatchService {
// The BatchService is a singleton service available throughout the app.

private apiUrl = 'https://your-api-url.com/data'; // Backend API URL


private batchSize = 10; // Number of items to send in each batch.

constructor(private http: HttpClient) {}


// Injects Angular's HttpClient to send API requests.

sendBulkDataInBatches(data: any[]): Observable<any[]> {


// Method to process and send bulk data in batches as an observable.

return new Observable((observer: Observer<any[]>) => {


// Creates a custom Observable to handle batch processing.

const batches = this.chunkArray(data, this.batchSize);


// Splits the input data into smaller chunks (batches) of the specified size.

from(batches) // Converts batches into a stream of Observables.


.pipe(
mergeMap((batch) => this.sendBatch(batch), 1),
// Processes each batch sequentially (concurrency = 1).
toArray()
// Collects results of all batches into a single array.
)
.subscribe({
next: (results) => observer.next(results),
// Emits all processed batch results.
error: (err) => observer.error(err),
// Emits an error if any batch fails.
complete: () => observer.complete(),
// Completes once all batches are processed.
});
});
}

private sendBatch(batch: any[]): Observable<any> {


// Sends a single batch to the API.
return this.http.post(this.apiUrl, batch).pipe(delay(500));
// Sends the data using HTTP POST and delays 500ms for throttling.
}

private chunkArray(array: any[], size: number): any[][] {


// Splits the given array into smaller arrays of specified size.
const chunks = [];
for (let i = 0; i < array.length; i += size) {
chunks.push(array.slice(i, i + size));
}
return chunks;
// Returns an array of chunks.
}
}

Observable + Observer Role

1. Breaking into Batches:

o The Observable emits each batch (from(batches)).

2. Processing Each Batch:

o Each batch is sent sequentially to the API (mergeMap + sendBatch).

o Results are emitted as they are processed.

3. Handling Results:

o The Observer receives results (next), handles errors for each batch and marks the
process as complete once all batches are complete.

In essence, the Observable represents the asynchronous batch upload process, and the Observer
reacts to its outcomes.

21.2) Promise
A Promise is an object in JavaScript that represents the eventual completion or failure of an
asynchronous operation.

Analogy:

 Imagine you order food at a restaurant.

o The Promise is the order you place.

o The Resolve is when the food arrives (successful completion).

o The Reject is if the restaurant says they ran out of food (failure).

function fetchData() {
return new Promise((resolve, reject) => {
// Simulate a network request with a timeout
setTimeout(() => {
const success = true; // Change this to false to simulate a failure

if (success) {
resolve("Data fetched successfully!"); // The task was successful
} else {
reject("Error fetching data."); // The task failed
}
}, 2000); // Simulates a 2-second delay
});
}

// Using the Promise


fetchData()
.then((data) => {
console.log(data); // If resolved, this will log the success message
})
.catch((error) => {
console.log(error); // If rejected, this will log the error message
});
21.3) operators
1. Forkjoin
Helps in making mulitple api calls for parellel execution, refer above code

2. Creation operators

These are used to create new observables.

of:
Creates an observable that emits a fixed number of values.

import { of } from 'rxjs';

const obs$ = of(1, 2, 3);

obs$.subscribe(value => console.log(value)); // Output: 1, 2, 3

from:
Converts an array, promise, or iterable into an observable.

import { from } from 'rxjs';

const obs$ = from([10, 20, 30]);

obs$.subscribe(value => console.log(value)); // Output: 10, 20, 30


3 Combination Operators
Used to combine multiple observables.

concat:
Concatenates multiple observables sequentially.

import { of, concat } from 'rxjs';

const obs1$ = of(1, 2);

const obs2$ = of(3, 4);

const combined$ = concat(obs1$, obs2$);

combined$.subscribe(value => console.log(value)); // Output: 1, 2, 3, 4

merge:
Merges multiple observables concurrently.

import { of, merge } from 'rxjs';

const obs1$ = of(1, 2);

const obs2$ = of(3, 4);

const merged$ = merge(obs1$, obs2$);

merged$.subscribe(value => console.log(value)); // Output: 1, 3, 2, 4

4. Transformation Operators

map:
Applies a function to each emitted value.

import { of } from 'rxjs';


import { map } from 'rxjs/operators';

const obs$ = of(1, 2, 3).pipe(map(x => x * 2));


obs$.subscribe(value => console.log(value)); // Output: 2, 4, 6

5. Filtering Operators

filter:
Filters values based on a condition.
import { of } from 'rxjs';

import { filter } from 'rxjs/operators';

const obs$ = of(1, 2, 3, 4).pipe(filter(x => x % 2 === 0));

obs$.subscribe(value => console.log(value)); // Output: 2, 4

6. Pipe, tap operators

The pipe method is used to chain RxJS operators to an observable

import { Component, OnInit } from '@angular/core';


import { Observable, of } from 'rxjs';
import { map, filter } from 'rxjs/operators';

@Component({
selector: 'app-pipe-example',
template: `<div>{{ result }}</div>`
})
export class PipeExampleComponent implements OnInit {
result: number;

ngOnInit() {
// Create an observable with an array of numbers
const numbers$: Observable<number[]> = of([1, 2, 3, 4, 5]);

numbers$.pipe(
// First operator: filter out even numbers
filter(numbers => numbers.some(num => num % 2 === 0)),
// Second operator: multiply each number by 2
map(numbers => numbers.map(num => num * 2))
).subscribe(filteredNumbers => {
this.result = filteredNumbers[0]; // Display the first transformed number
});
}
}

tap is commonly used for debugging, logging, or triggering actions but doesn't alter the
stream.
Difference between tap and console.log is - tap is used in rxjs observable pipeline,
whereas consol.log can be used anywhere in the code

import { Component, OnInit } from '@angular/core';


import { Observable, of } from 'rxjs';
import { map, tap } from 'rxjs/operators';

@Component({
selector: 'app-tap-example',
template: `<div>{{ result }}</div>`
})
export class TapExampleComponent implements OnInit {
result: number;

ngOnInit() {
// Create an observable with an array of numbers
const numbers$: Observable<number[]> = of([1, 2, 3, 4, 5]);

numbers$.pipe(
// `tap` is used for logging the numbers without altering the stream
tap(numbers => console.log('Before transformation:', numbers)),
// `map` is used to transform the numbers by doubling them
map(numbers => numbers.map(num => num * 2)),
// `tap` can be used again to log after transformation
tap(numbers => console.log('After transformation:', numbers))
).subscribe(transformedNumbers => {
this.result = transformedNumbers[0]; // Display the first transformed number
});
}
}

Analogy

Observable - coffee
Pipe – coffe making process
Tap- coffee tasting

7. Debouncing

Debounce is a technique to delaying its execution until a specified period of


inactivity

21) Block and Inline in html

A block-level element always starts on a new line - <p> <div>

Inline element doesn’t start on new line - <span> <a> <b>

22) Angular Project architecture


Architecture diagram
src/

├── app/
│ ├── core/ # Core module (singleton services, guards, interceptors)

│ │ ├── auth.service.ts # Example: Authentication service

│ │ ├── logging.service.ts # Example: Logging service

│ │ ├── auth.guard.ts # Example: Auth guard for route protection

│ │ ├── core.module.ts # Core module to provide global services

│ │ └── ...

│ ├── shared/ # Shared module (reusable components, pipes, directives)

│ │ ├── button/ # Example shared component

│ │ │ ├── button.component.ts

│ │ │ ├── button.component.html

│ │ │ └── button.component.css

│ │ ├── pipes/

│ │ │ ├── date-format.pipe.ts # Example pipe

│ │ │ └── ...

│ │ ├── shared.module.ts # Shared module to export reusable components, pipes

│ │ └── ...

│ ├── employee/ # Feature module: Employee management

│ │ ├── employee-list/ # Employee list component

│ │ │ ├── employee-list.component.ts

│ │ │ ├── employee-list.component.html

│ │ │ └── employee-list.component.css

│ │ ├── employee-details/ # Employee details component

│ │ ├── employee.service.ts # Employee service for API calls

│ │ ├── employee-routing.module.ts # Routing for employee features

│ │ ├── employee.module.ts # Feature module for employee

│ │ └── ...

│ ├── customer/ # Feature module: Customer management

│ │ ├── customer-list/ # Customer list component

│ │ ├── customer-details/ # Customer details component

│ │ ├── customer.service.ts # Customer service for API calls

│ │ ├── customer-routing.module.ts # Routing for customer features


│ │ ├── customer.module.ts # Feature module for customer

│ │ └── ...

│ ├── order/ # Feature module: Order management

│ │ ├── order-list/ # Order list component

│ │ ├── order-details/ # Order details component

│ │ ├── order.service.ts # Order service for API calls

│ │ ├── order-routing.module.ts # Routing for order features

│ │ ├── order.module.ts # Feature module for order

│ │ └── ...

│ ├── app-routing.module.ts # App-level routing configuration

│ ├── app.component.ts # Root component

│ ├── app.module.ts # Main app module

│ └── ...

├── assets/ # Static assets (images, icons, etc.)

├── environments/ # Environment-specific configurations (e.g., prod, dev)

├── styles/ # Global styles (CSS/SCSS files)

└── index.html # Main HTML file

How app.module.ts looks

import { NgModule } from '@angular/core';


import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module'; // App-level routing
import { CoreModule } from './core/core.module'; // Core module for app-wide
services (e.g., Auth, Interceptors)
import { SharedModule } from './shared/shared.module'; // Shared module for
reusable components, pipes, etc.
import { EmployeeModule } from './employee/employee.module'; // Feature module
for Employee management
import { CustomerModule } from './customer/customer.module'; // Feature module
for Customer management
import { OrderModule } from './order/order.module'; // Feature module for
Order management
import { AppComponent } from './app.component'; // Root component of the
app

@NgModule({
declarations: [
AppComponent, // Root component
],
imports: [
BrowserModule, // Required for any Angular app
AppRoutingModule, // App-level routing (manages navigation across the app)
CoreModule, // Core module for global services (e.g., Auth, HTTP
interceptors)
SharedModule, // Shared module for reusable components (e.g., buttons,
tables, etc.)
EmployeeModule, // Feature module for Employee management
CustomerModule, // Feature module for Customer management
OrderModule, // Feature module for Order management
],
providers: [], // Providers for app-wide services (typically in CoreModule)
bootstrap: [AppComponent] // Bootstrapping the app with the root component
})
export class AppModule {}

How app-routing.module.ts looks

const routes: Routes = [

{ path: '', redirectTo: '/employee', pathMatch: 'full' },

{ path: 'employee', loadChildren: () => import('./employee/employee.module').then(m =>


m.EmployeeModule) },

{ path: 'customer', loadChildren: () => import('./customer/customer.module').then(m =>


m.CustomerModule) },

{ path: 'order', loadChildren: () => import('./order/order.module').then(m => m.OrderModule) },

// other global routes like login, error pages, etc.

];

@NgModule({

imports: [RouterModule.forRoot(routes)],

exports: [RouterModule]

})

export class AppRoutingModule {}

Core Module
The Core module should contain services, guards, interceptors, and other singleton objects that are
used across the entire application. These should only be imported into the AppModule.
 Services (e.g., authentication, logging, HTTP interceptors)

 Guards (for route protection)

 HTTP Interceptors (for adding authorization tokens or handling errors globally)

core.module.ts:

@NgModule({

providers: [

AuthService,

LoggingService,

AuthGuard,

HTTP_INTERCEPTORS,

ErrorInterceptor,

],

imports: [CommonModule]

})

export class CoreModule {}

Shared Module
The Shared module is where you place reusable components, directives, pipes, and other logic that
could be shared across multiple feature modules. For instance, buttons, cards, modals, etc.

 Components (e.g., reusable button, modal, table)

 Directives (e.g., input validation directives)

 Pipes (e.g., date formatting, currency formatting)

shared.module.ts:

@NgModule({

declarations: [SharedComponent, SharedDirective],

exports: [SharedComponent, SharedDirective],

imports: [CommonModule],

})

export class SharedModule {}

Feature Modules
For each screen (Employee, Customer, Order), create a feature module. Each feature module should
be responsible for managing its own components, services, and routing.

a. Employee Module (employee.module.ts):


 Components: Employee list, employee details, employee edit

 Services: Employee data service to fetch employee data from the backend

 Routing: Define routes for employee-related screens

@NgModule({

declarations: [EmployeeListComponent, EmployeeDetailsComponent],

imports: [CommonModule, EmployeeRoutingModule, SharedModule],

providers: [EmployeeService],

})

export class EmployeeModule {}

Concept of shared module


 If you've already imported the SharedModule into app.module.ts, feature modules don't
need to import it separately.
 If SharedModule isn't imported into app.module.ts, then you must import it separately in
each feature module where you need to use shared components.

23) Change detection in Angular


Change detection in Angular is the mechanism that keeps the user interface (UI) in
sync with the application's data model.
Key Concepts of Change Detection
1. Component Tree: Angular apps are built with components organized in a tree structure. Each
component has its own change detection cycle.
2. Zones: Angular uses a library called Zone.js to track asynchronous operations (e.g., HTTP
requests, timers) and trigger change detection when necessary.
Strategies for Change detection :-

Basic Example

1. Default Change Detection


In the default strategy, Angular automatically detects changes in the data and
updates the UI.

HTML (app.component.html):
<h1>{{ counter }}</h1>
<button (click)="increment()">Increment</button>

Component (app.component.ts):
import { Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
counter = 0;

increment() {
this.counter++;
}
}
 When you click the button, the increment method is called, updating the counter. Angular
automatically detects this change and updates the <h1> element.

2. OnPush Change Detection Strategy


Using the OnPush strategy, Angular only checks for changes if the @Input() property
of a component changes or if you explicitly trigger change detection.

Parent Component (app.component.ts):


import { Component } from '@angular/core';

@Component({
selector: 'app-root',
template: `
<app-child [counter]="counter"></app-child>
<button (click)="increment()">Increment</button>
`,
styleUrls: ['./app.component.css'],
})
export class AppComponent {
counter = 0;

increment() {
this.counter++;
}
}
Child Component (child.component.ts):
import { Component, Input, ChangeDetectionStrategy } from '@angular/core';

@Component({
selector: 'app-child',
template: '<h1>{{ counter }}</h1>',
changeDetection: ChangeDetectionStrategy.OnPush, // Enable OnPush strategy
})
export class ChildComponent {
@Input() counter!: number;
}
Here, the child component will only detect changes if:
 The counter value is passed as a new reference (e.g., a new object or primitive value).
 Only for input property change change is detected and view is updated, rest all other
changes in both parent and child component change detections is skipped. This improves
performance of application

3. Manual Change Detection with ChangeDetectorRef


You can manually trigger change detection in cases where Angular doesn't detect
changes automatically.
Example: Suppose you update a variable inside a setTimeout without triggering
Angular's default detection.
import { Component, ChangeDetectorRef } from '@angular/core';

@Component({
selector: 'app-root',
template: `<h1>{{ message }}</h1>`,
styleUrls: ['./app.component.css'],
})
export class AppComponent {
message = 'Hello, Angular!';

constructor(private cdr: ChangeDetectorRef) {


setTimeout(() => {
this.message = 'Updated Message!';
this.cdr.detectChanges()/markForCheck(); // Manually trigger change detection
}, 3000);
}
}
Without cdr.detectChanges(), the UI would not update after the setTimeout.

Summary
 Default Strategy: Angular automatically detects all changes in the component tree.
 OnPush Strategy: Angular only checks changes for specific inputs or manual triggers,
improving performance.
 Manual Detection: Use ChangeDetectorRef when Angular's default mechanism is not
sufficient.

Important Note-

 In Angular, the root component (AppComponent) is at the top of the component tree, and
any changes in it can trigger change detection in the entire application to check its child
component. This is the default behaviour of change detection. To overcome this, we use
ChangeDetectionStrategy.OnPush.
 Hence, any change in the parent component will trigger change detection for all its child
components
 In Angular, change detection flows downwards from the parent to its child components, not
the other way around.

24) Advanced reactive form


import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, FormArray, Validators, AbstractControl } from
'@angular/forms';

@Component({
selector: 'app-advanced-reactive-form',
template: `
<form [formGroup]="userForm" (ngSubmit)="onSubmit()">
<div>
<label>First Name:</label>
<input formControlName="firstName" />
<div *ngIf="firstName.invalid && firstName.touched">First Name is
required.</div>
<p *ngIf="firstName.dirty">First Name field is dirty (modified).</p>
<p *ngIf="firstName.pristine">First Name field is pristine (unchanged).</p>
</div>

<div>
<label>Email:</label>
<input formControlName="email" />
<div *ngIf="email.invalid && email.touched">Invalid Email Address.</div>
</div>

<div>
<label>Age:</label>
<input formControlName="age" type="number" />
<div *ngIf="age.invalid && age.touched">Age must be between 18 and
60.</div>
</div>

<div formArrayName="skills">
<label>Skills:</label>
<div *ngFor="let skill of skills.controls; let i = index">
<input [formControlName]="i" placeholder="Skill {{ i + 1 }}" />
</div>
<button type="button" (click)="addSkill()">Add Skill</button>
</div>

<button type="button" (click)="setInitialValues()">Set Initial Values</button>


<button type="button" (click)="updateEmail()">Update Email Only
(Patch)</button>
<button type="button" (click)="resetForm()">Reset Form</button>
<button type="submit" [disabled]="userForm.invalid">Submit</button>
</form>
`,
})
export class AdvancedReactiveFormComponent implements OnInit {
// Create the form using FormGroup
// Groups related controls like firstName, email, and skills
userForm = new FormGroup({
firstName: new FormControl('', Validators.required), // Required validation
email: new FormControl('', [Validators.required, Validators.email]), // Email
validation
age: new FormControl('', [Validators.required, Validators.min(18),
Validators.max(60)]), // Age validation
skills: new FormArray([new FormControl('')]), // Dynamic array for skills
});
//formcontrol - Tracks the value, touched state, and validation of these individual
fields.

ngOnInit(): void {
// **valueChanges**: Emits an observable whenever the form values change
this.userForm.valueChanges.subscribe((value) => {
console.log('Form Value Changed:', value); // Logs the current value of the form
});

// **statusChanges**: Emits an observable whenever the form status (VALID,


INVALID) changes
this.userForm.statusChanges.subscribe((status) => {
console.log('Form Status Changed:', status); // Logs the current status of the form
});
}

// Getters for easier access to controls, accessed by valid, invlaid, touched, dirty,
pristine
get firstName(): AbstractControl {
return this.userForm.get('firstName')!;
}

get email(): AbstractControl {


return this.userForm.get('email')!;
}

get age(): AbstractControl {


return this.userForm.get('age')!;
}

get skills(): FormArray {


return this.userForm.get('skills') as FormArray;
}

// Method to add a new skill to the FormArray


//form array - adds/removes formcontrols dynamically
addSkill() {
this.skills.push(new FormControl(''));
}

// **setValue**: Updates the entire form with exact values for each field
setInitialValues() {
this.userForm.setValue({
firstName: 'John',
email: '[email protected]',
age: 30,
skills: ['Angular', 'React'], // All form controls must be provided
});
console.log('Form values set using setValue:', this.userForm.value);
}

// **patchValue**: Updates specific fields without affecting other fields


updateEmail() {
this.userForm.patchValue({
email: '[email protected]', // Only the email field is updated
});
console.log('Email updated using patchValue:', this.userForm.value);
}

// Method to reset the form


resetForm() {
// **dirty**: Indicates if the control/form has been modified
// **pristine**: Indicates if the control/form remains unchanged
this.userForm.reset({
firstName: '',
email: '',
age: '',
skills: [''], // Resets the form with an empty skill field
});
console.log('Form reset:', this.userForm.value);
}

// Handle form submission


onSubmit() {
if (this.userForm.valid) {
console.log('Form Submitted', this.userForm.value);
} else {
this.userForm.markAllAsTouched(); // Marks all controls as touched to show
validation errors
}
}
}

25) Exception handling in angular


Step 1: Create a Custom Global Error Handler
This class extends Angular's ErrorHandler and handles exceptions globally.
import { ErrorHandler, Injectable } from '@angular/core';

@Injectable()
export class GlobalErrorHandlerService implements ErrorHandler {
handleError(error: any): void {
// Log the error (to console or a logging service)
console.error('Global Error Caught:', error);

// Optionally log error details to a server


// this.logErrorToServer(error);

// Show a user-friendly message


alert('An unexpected error occurred. Please try again later.');

// Re-throw the error if needed for debugging (optional)


// throw error;
}

// Example method to log error to the server (optional)


private logErrorToServer(error: any): void {
// You can use an HTTP service to send error details to your server
// Example: this.http.post('https://your-server.com/errors',
errorDetails).subscribe();
console.log('Error logged to server:', error);
}
}

Step 2: Register the Global Error Handler in AppModule


You need to tell Angular to use your custom error handler instead of the default one.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { GlobalErrorHandlerService } from './global-error-handler.service';
import { ErrorHandler } from '@angular/core';

@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [
{
provide: ErrorHandler, // Replace the default ErrorHandler
useClass: GlobalErrorHandlerService, // Use the custom
GlobalErrorHandlerService
},
],
bootstrap: [AppComponent],
})
export class AppModule {}

step 3 : handle exception in error block

import { Component, OnInit } from '@angular/core';


import { HttpClient } from '@angular/common/http';

@Component({
selector: 'app-root',
template: `
<h1>Global Exception Handling in Angular</h1>
<p *ngIf="data">Data: {{ data }}</p>
<p *ngIf="errorMessage" style="color: red;">Error: {{ errorMessage }}</p>
`,
})
export class AppComponent implements OnInit {
data: any;
errorMessage: string | null = null;

constructor(private http: HttpClient) {}

ngOnInit(): void {
// Simulate an API call
this.getDataFromApi();
}

getDataFromApi(): void {
// Intentionally use an invalid API URL to trigger an error
this.http.get('https://invalid-api-url.com/data').subscribe({
next: (response) => {
this.data = response;
},
error: (error) => {
console.error('Local Error Caught:', error);
this.errorMessage = 'Failed to load data!';
throw error; // Re-throw to trigger the global error handler, it is optional to use
},
});
}
}
26) Http Protocols
 HTTP (HyperText Transfer Protocol):
o Data is sent over the network in plain text.
o It is not secure, which means the data being transferred can be intercepted or
modified by attackers.
 HTTPS (HyperText Transfer Protocol Secure):
o Data is encrypted using TLS/SSL (Transport Layer Security/Secure Sockets Layer).
o It ensures secure communication between the client and the serve

27) Angular migrations


1. Check Current Angular Version: Run ng version to know your starting
version.
2. Review Angular Update Guide: Use the Angular Update Guide for version-
specific steps.
3. Update Angular CLI:
 Update globally: npm install -g @angular/cli@latest.
 Update locally: ng update @angular/cli.
4. Update Angular Core: Run ng update @angular/core.
5. Update Third-Party Dependencies: Check outdated libraries using npm
outdated and update them.
6. Fix Compatibility Issues: Resolve any warnings or errors after the update.
7. Update RxJS (If Required): Use ng update rxjs for RxJS updates.
8. Test Your Application: Run ng test and ng e2e to verify functionality.
9. Clean Project: Delete node_modules and reinstall dependencies (npm
install).
10. Rebuild and Deploy: Run ng build --prod and deploy the updated app.

Common errors we face in migration

1. Typescript errors, upgrade to recommended version


2. Template errors, might need to take care on sytax things like ngif, ngfor
3. Third party libraries upgradation
4. Update rxjs
5. Delete and re-install node modules
28) Explain the difference between Subject
and BehaviorSubject.

29) Explain the concept of a router template


in Angular.
<!-- This is the Router Template (Placeholder for Routed Components) -->

<router-outlet></router-outlet>

30) If we have three tabs opens means how


many session storage we have

31) What is position property, what is the


differences between static, relative, absolute
and fixes

32) What is closure(as encapsulation in C#)

Using Closure in an Angular Service


Closures are useful in Angular services to maintain state without exposing variables directly.
auth.service.ts
import { Injectable } from '@angular/core';

@Injectable({
providedIn: 'root'
})
export class AuthService {
private user = ''; // Private variable

getUser() {
return () => this.user; // Closure that retains access to `user`
}

setUser(username: string) {
this.user = username;
}
}
app.component.ts
import { Component } from '@angular/core';
import { AuthService } from './auth.service';

@Component({
selector: 'app-root',
template: `
<button (click)="login()">Login</button>
<p>User: {{ getUser() }}</p>
`
})
export class AppComponent {
getUser: () => string;

constructor(private authService: AuthService) {


this.getUser = this.authService.getUser(); // Closure retains user state
}

login() {
this.authService.setUser('JohnDoe');
}
}
How It Works?
 The AuthService method getUser() returns a closure that retains access to user.
 Even when AppComponent assigns getUser, the function remembers the user variable.
✅ Closures help manage and encapsulate state!

33) What is hoisting in JavaScript

34) What is event loop

35) How do you implement validation in


Angular forms (template-driven and reactive
forms)

36) Asynchronous and Synchronous calls in


angular
Asynchronous:
Code does not wait for the previous operation to finish. It continues executing, while the previous
operation completes in the background (e.g., API calls, setTimeout, etc.).

Examples – Api calls, setTimeout

Api calls
ngOnInit() {

console.log("Fetching data...");

this.dataService.getData().subscribe(response => {
console.log("Data received:", response);
});
console.log("Request sent, waiting for response...");

O/P
Fetching data...
Request sent, waiting for response...
Data received: [ { id: 1, title: "Post 1" }, { id: 2, title: "Post 2" }, ... ]

setTimeout
console.log("Step 1: Start");

setTimeout(() => {
console.log("Step 2: Processing (Delayed)");
}, 2000); // Simulates delay of 2 seconds
console.log("Step 3: End");

O/P

Step 1: Start
Step 3: End
Step 2: Processing (Delayed) // This appears after 2 seconds

Synchronous:

Code executes line by line, one after another. The next line of code waits for the previous one to
complete.

Example
function login(username: string, password: string): boolean {
console.log("Verifying user credentials...");

// Synchronous check (just an example)


if (username === "admin" && password === "1234") {
console.log("Login successful!");
return true;
} else {
console.log("Login failed!");
return false;
}
}

console.log("Step 1: User tries to login");


const isAuthenticated = login("admin", "1234"); // Blocks execution
console.log("Step 2: Redirect user based on login status");

O/P
Step 1: User tries to login
Verifying user credentials...
Login successful!
Step 2: Redirect user based on login status

37) setTimeout and setInterval in angular


setTimeout - Executes a function once after a delay.
import { Component, OnInit } from '@angular/core';

@Component({
selector: 'app-timeout-example',
template: '<p>{{ message }}</p>'
})
export class TimeoutExampleComponent implements OnInit {
message: string = "Waiting...";

ngOnInit() {
console.log("Step 1: Timer started...");

setTimeout(() => {
this.message = "Hello after 3 seconds!";
console.log("Step 2: Message updated!");
}, 3000); // 3 seconds delay
}
}

O/P
Step 1: Timer started...
(After 3 seconds)
Step 2: Message updated!

setInterval - Repeats a function at fixed intervals


import { Component, OnInit, OnDestroy } from '@angular/core';

@Component({
selector: 'app-interval-example',
template: '<p>Current Time: {{ currentTime }}</p>'
})
export class IntervalExampleComponent implements OnInit, OnDestroy {
currentTime: string = new Date().toLocaleTimeString();
intervalId: any;

ngOnInit() {
console.log("Clock started...");

this.intervalId = setInterval(() => {


this.currentTime = new Date().toLocaleTimeString();
console.log("Updated time:", this.currentTime);
}, 1000); // Updates every 1 second
}

ngOnDestroy() {
clearInterval(this.intervalId); // Stops the interval when component is destroyed
console.log("Clock stopped!");
}
}

O/P

Clock started...
Updated time: 10:00:01 AM
Updated time: 10:00:02 AM
Updated time: 10:00:03 AM
(Updates every second)

38) Call back function

Here, function is passed as parameter and called back in another function

function orderPizza(callback: (message: string) => void) {


console.log("Step 1: Order placed. Preparing pizza...");

setTimeout(() => {
console.log("Step 2: Pizza is ready!");
callback("Enjoy your pizza! 🍕"); // Calling the callback function
}, 3000); // Simulating 3 seconds pizza preparation time
}

function eatPizza(message: string) {


console.log("Step 3:", message);
}

// Placing an order and passing the callback function


orderPizza(eatPizza);

O/P
Step 1: Order placed. Preparing pizza...
(After 3 seconds)
Step 2: Pizza is ready!
Step 3: Enjoy your pizza! 🍕
39) Async await in angular

Asynchronous call –

ngOnInit() {

console.log("Fetching data...");

this.dataService.getData().subscribe(response => {
console.log("Data received:", response);
});

console.log("Request sent, waiting for response...");

}
Here, api call is asynchronous, as it don’t block the further execution, but this is some times not
beneficial.

Hence, this can be overcome by converting above code to synchronous using async, await and
lastValueFrom() [converts observable to promise]

synchronous call –

Step 1: Create the Service (data.service.ts)


This service will fetch data from a dummy API (JSONPlaceholder).
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
providedIn: 'root'
})
export class DataService {
private apiUrl = 'https://jsonplaceholder.typicode.com/posts/1'; // Dummy API

constructor(private http: HttpClient) {}

getData(): Observable<any> {
return this.http.get<any>(this.apiUrl);
}
}

Step 2: Use lastValueFrom() in app.component.ts


We'll use async-await to make the call synchronous.
import { Component, OnInit } from '@angular/core';
import { DataService } from './data.service';
import { lastValueFrom } from 'rxjs';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
constructor(private dataService: DataService) {}

async ngOnInit() {
console.log("Fetching data...");

try {
const response = await lastValueFrom(this.dataService.getData());
console.log("Data received:", response);
} catch (error) {
console.error("Error fetching data:", error);
}

console.log("Request completed.");
}
}

40) Content projection and it’s types

1️. Single-Slot Content Projection


👉 All content from the parent is placed inside <ng-content> in the child.

Child Component (child.component.html)


<div class="box">
<h3>Child Component</h3>
<ng-content></ng-content> <!-- Everything inside <app-child> will appear here -->
</div>

Parent Component (app.component.html)


<h2>Single-Slot Projection Example</h2>
<app-child>
<p>This content comes from the parent.</p>
</app-child>

Expected Output
📌 What you will see in the browser
Single-Slot Projection Example
--------------------------------
Child Component
This content comes from the parent.
2. Projecting Components Inside <ng-content>
👉 You can pass Angular components inside <ng-content>.
Other Component (other.component.html)
<div class="other-box">
<p>This is another component!</p>
</div>

Child Component (child.component.html)


<div class="container">
<h3>Child Component</h3>
<ng-content></ng-content> <!-- Other component will appear here -->
</div>

Parent Component (app.component.html)


<h2>Component Projection Example</h2>
<app-child>
<app-other></app-other>
</app-child>

Expected Output
📌 What you will see in the browser
Component Projection Example
--------------------------------
Child Component
This is another component!

3. Multi-Slot Content Projection – In scenarios where modal popup


is reused
Step 1: Create a Modal Component (Child Component)
Let's start by building a ModalComponent that has three sections: Header, Body, and Footer.
<!-- modal.component.html -->
<div class="modal">
<div class="modal-header">
<ng-content select=".modal-header"></ng-content> <!-- For Header -->
</div>

<div class="modal-body">
<ng-content select=".modal-body"></ng-content> <!-- For Body -->
</div>

<div class="modal-footer">
<ng-content select=".modal-footer"></ng-content> <!-- For Footer -->
</div>
</div>

Select attribute is mainly used for custome class having css code
Add Some Basic Styling for the Modal:

/* modal.component.css */
.modal {
background: white;
border-radius: 5px;
padding: 20px;
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
}

.modal-header {
font-size: 20px;
font-weight: bold;
margin-bottom: 10px;
}

.modal-body {
font-size: 16px;
margin-bottom: 20px;
}

.modal-footer {
text-align: right;
}

Step 2: Use the Modal Component in the Parent


In the parent component, you'll use the <app-modal> and provide content for each section (Header,
Body, Footer) using the respective class names.

<!-- app.component.html -->

<h2>Modal Example with Multi-Slot Content Projection</h2>

<app-modal>

<div class="modal-header">Welcome to My Modal</div> <!-- Header content -->

<div class="modal-body">Here is the main content of the modal. You can put any message or form
here.</div> <!-- Body content -->

<div class="modal-footer">

<button (click)="closeModal()">Cancel</button> <!-- Footer content -->

<button (click)="confirmAction()">OK</button>

</div>

</app-modal>
<app-modal>

<div class="modal-header">Error Occurred!</div> <!-- Header content -->

<div class="modal-body">Something went wrong. Please try again later.</div> <!-- Body content -->

<div class="modal-footer">

<button (click)="closeModal()">Close</button> <!-- Footer content -->

</div>

</app-modal>

41) Default files in angular

You might also like