0% found this document useful (0 votes)
9 views30 pages

Fullstack-2

The document provides an in-depth overview of the Angular framework, highlighting its components, directives, services, and advanced topics such as state management with NgRx and RxJS for reactive programming. It also covers TypeScript features essential for building robust applications and the integration of Node.js and Express.js for backend development. Key concepts include dependency injection, lazy loading, and custom life-cycle hooks, aimed at enhancing application performance and maintainability.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views30 pages

Fullstack-2

The document provides an in-depth overview of the Angular framework, highlighting its components, directives, services, and advanced topics such as state management with NgRx and RxJS for reactive programming. It also covers TypeScript features essential for building robust applications and the integration of Node.js and Express.js for backend development. Key concepts include dependency injection, lazy loading, and custom life-cycle hooks, aimed at enhancing application performance and maintainability.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 30

1 Deep Dive into Angular Framework

1. Deep Dive into Angular Framework 12 CO1


Angular 12 is a robust framework used for building dynamic, single-page web
applications. It includes features like TypeScript support, dependency
injection, and RxJS for reactive programming. Let’s dive into its components:

1.1 Recap of Angular Fundamentals


Understanding the foundational concepts of Angular is crucial before diving
deeper.
1. Components:
o Angular applications are built with components.
o Each component controls a section of the UI and consists of:
 HTML Template: Defines the layout.
 TypeScript Class: Contains logic.
 CSS Styles: Defines the look and feel.
o Example:
o @Component({
o selector: 'app-example',
o templateUrl: './example.component.html',
o styleUrls: ['./example.component.css']
o })
o export class ExampleComponent {
o title = 'Hello Angular!';
o }
2. Directives:
o Custom HTML attributes used to manipulate DOM elements.
o Structural Directives: Alter the layout, e.g., *ngIf, *ngFor.
o Attribute Directives: Change the appearance, e.g., ngClass,
ngStyle.
3. Services:
o Used for sharing logic and data between components.
o Implemented using dependency injection.
o Example service:
o @Injectable({
o providedIn: 'root'
o })
o export class DataService {
o getData() { return ['Item1', 'Item2']; }
o }
4. Dependency Injection (DI):
o A design pattern where Angular provides dependencies (like
services) to components automatically.
o Ensures modularity and easy testing.

1.2 Introduction to Advanced Topics Covered in the Course


This course delves deeper into Angular's ecosystem, including:
 State Management: Using libraries like NgRx for managing
application state.
 Lazy Loading: Efficient loading of modules for better
performance.
 Dynamic Component Loading: Loading components dynamically
at runtime.
 Unit Testing: Writing tests for components and services.
 Server-Side Rendering (SSR): Using Angular Universal for SEO-
friendly applications.
1.3 Prerequisite Knowledge Refresher
A strong foundation in related technologies is necessary.
1. ES6:
o Modern JavaScript features like let, const, arrow functions,
template literals, destructuring, and modules.
o Example:
o const add = (a, b) => a + b;
2. TypeScript:
o A superset of JavaScript adding types and interfaces.
o Example:
o let message: string = "Hello";
3. Node.js:
o JavaScript runtime for building backend applications.
o Used with Angular for development servers or full-stack apps.
4. Express.js:
o A lightweight web application framework for Node.js.
o Used to create REST APIs.
5. MongoDB:
o NoSQL database for storing application data.

1.4 Introduction to RxJS Library


RxJS (Reactive Extensions for JavaScript) is a library for reactive
programming using observables, providing powerful tools for asynchronous
operations.
1.4.1 Observable
 Represents a stream of data that can be observed.
 Emits values over time.
 Example:
 const observable = new Observable(observer => {
 observer.next('First Value');
 observer.complete();
 });
 observable.subscribe(val => console.log(val));
1.4.2 Observer
 An entity that consumes values emitted by an observable.
 Contains methods like next(), error(), and complete().
1.4.3 Subscription
 Represents the execution of an observable.
 Used to start and stop receiving data.
 Example:
 const subscription = observable.subscribe({
 next: value => console.log(value),
 complete: () => console.log('Completed')
 });
 subscription.unsubscribe(); // Stops observing
1.4.4 Operators
 Functions used to manipulate observable streams (e.g., map, filter,
merge).
 Example:
 from([1, 2, 3]).pipe(
 map(x => x * 2)
 ).subscribe(val => console.log(val));
1.4.5 Subject
 A special type of observable that acts as both observer and
observable.
 Can multicast to multiple observers.
 Example:
 const subject = new Subject<number>();
 subject.subscribe(value => console.log('Observer 1:', value));
 subject.next(1);
1.4.6 Schedulers
 Controls the execution of an observable by deciding when and how
its emissions occur.
 Examples: asyncScheduler, queueScheduler.

1.5 State Management with NgRx


NgRx is a reactive state management library for Angular applications, built on
the principles of Redux. It provides a predictable state container.

1.5.1 @ngrx/store
 Core of NgRx: Manages application state using a single immutable
state tree.
 Actions: Describe what to do (e.g., ADD_ITEM).
 Reducers: Describe how the state changes in response to actions.
 Selectors: Retrieve slices of the state efficiently.
 Example:
 export const addItem = createAction('[Items] Add Item', props<{
item: string }>());
 export const itemsReducer = createReducer([], on(addItem, (state, {
item }) => [...state, item]));
1.5.2 @ngrx/effects
 Handles Side Effects: For asynchronous operations like API calls
or logging.
 Key Feature: Keeps side effects outside reducers.
 Example:
 @Injectable()
 export class ItemsEffects {
 loadItems$ = createEffect(() =>
 this.actions$.pipe(
 ofType(loadItems),
 switchMap(() => this.http.get('/api/items').pipe(map(items =>
loadItemsSuccess({ items }))))
 )
 );
 constructor(private actions$: Actions, private http: HttpClient) {}
 }

1.5.3 @ngrx/router-store
 Integration with Angular Router: Synchronizes router state with
NgRx store.
 Selectors: Access route-related data like parameters or query
strings.
 Example:
 const selectRouteParams = createSelector(selectRouterState,
(router) => router.state.params);
1.5.4 @ngrx/entity
 Simplifies Entity State Management: Provides helpers for
managing collections.
 Features:
o EntityAdapter: Create, update, and delete records in the
state.
 Example:
 export const adapter = createEntityAdapter<Item>();
 export const initialState = adapter.getInitialState();

1.5.5 @ngrx/component-store
 For Local State Management: Used for stateful Angular
components.
 Example:
 @Injectable()
 export class CounterStore extends ComponentStore<{ count:
number }> {
 constructor() {
 super({ count: 0 });
 }
 readonly increment = this.updater(state => ({ count: state.count +
1 }));
 }

1.5.6 @ngrx/signals
 Reactive Signals Integration: Enables state and event management
with reactive signal APIs.
 Useful for fine-grained reactivity in Angular components.
1.5.7 @ngrx/operators
 Utility Operators: Enhance observables for NgRx state
management.
 Examples: select, onErrorResumeNext.

1.5.8 @ngrx/data
 Simplifies CRUD Operations: Provides entity-specific services.
 Example:
 entityService.add(entity); // Adds a new entity

1.5.9 @ngrx/component
 Reactive Component Store: Supports component-based state and
reactivity.

1.5.10 Developer Tools


1. @ngrx/store-devtools:
o Debugging tools to visualize state changes.
o Example: Use Redux DevTools Extension.
2. @ngrx/schematics:
o Automates boilerplate code creation.
o Example: Generate actions, reducers, and effects.
3. @ngrx/eslint-plugin:
o Ensures NgRx code follows best practices.
1.6 Custom Life-cycle Hooks
 Beyond Angular’s Default Hooks: Custom hooks extend
Angular’s life-cycle methods.
 Example:
 export class MyComponent {
 onViewLoad() {
 console.log('Custom hook triggered');
 }
 }

1.7 Communication Between Components Beyond @Input() and


@Output()
 State Management: Use services or NgRx for shared state.
 EventEmitter: Emit custom events.
 RxJS Subjects: Facilitate cross-component communication.
 Example:
 const messageBus = new Subject<string>();
 messageBus.subscribe(msg => console.log(msg));

1.8 Advanced Routing Concepts


1. Lazy Loading:
o Load modules only when needed to improve performance.
o Example:
o { path: 'feature', loadChildren: () =>
import('./feature.module').then(m => m.FeatureModule) }
2. Nested Routes:
o Define child routes.
o Example:
o const routes: Routes = [{ path: 'parent', component:
ParentComponent, children: [{ path: 'child', component:
ChildComponent }] }];
3. Route Guards:
o Control access to routes.
o Types: CanActivate, CanDeactivate.
o Example:
o canActivate: [AuthGuard]
4. Resolvers:
o Pre-fetch data before navigating to a route.
o Example:
o resolve: { data: DataResolver }

1.9 Building Scalable and Reusable Features


1.9.1 Feature Modules and Lazy Loading
 Split application logic into smaller modules.
 Example: Create UserModule and load it on demand.
1.9.2 Creating Custom Directives and Pipes
 Directives: Manipulate DOM elements.
 Pipes: Transform data in templates.
 Example:
 @Pipe({ name: 'capitalize' })
 export class CapitalizePipe implements PipeTransform {
 transform(value: string): string {
 return value.toUpperCase();
 }
 }
1.9.3 Services for Data Fetching and Business Logic
 Separate business logic from components.
 Use HttpClient for API calls.
1.9.4 Dependency Injection Best Practices
 Avoid providing services at the component level unless necessary.
 Use interfaces for type safety.
2)Mastering TypeScript 4 CO2

2 Mastering TypeScript 4 CO2


TypeScript, a superset of JavaScript, adds static typing and other advanced
features to enhance the development experience and code quality. Mastering
these features is critical for building robust applications, especially in
frameworks like Angular.

2.1 Advanced TypeScript Features


2.1.1 Generics for Type Safety and Code Reusability
 Generics allow writing flexible and reusable components,
functions, or classes that work with any data type while maintaining
type safety.
 Example:
 function identity<T>(value: T): T {
 return value;
 }
 const numberIdentity = identity<number>(42); // Type-safe
 const stringIdentity = identity<string>('Hello'); // Type-safe
 Generics are commonly used in Angular services and libraries like
RxJS.

2.1.2 Decorators for Custom Functionality and Metadata


 Decorators are a special type of declaration that can be attached to
classes, methods, properties, or parameters.
 Common in Angular to add metadata to classes (e.g., @Component,
@Injectable).
 Example:
 function Log(target: any, propertyKey: string, descriptor:
PropertyDescriptor) {
 const originalMethod = descriptor.value;
 descriptor.value = function (...args: any[]) {
 console.log(`Called: ${propertyKey} with args: ${args}`);
 return originalMethod.apply(this, args);
 };
 }

 class Example {
 @Log
 greet(name: string) {
 return `Hello, ${name}`;
 }
 }
 const obj = new Example();
 obj.greet('TypeScript'); // Logs: Called: greet with args: [
'TypeScript' ]

2.1.3 Interfaces and Advanced Type Annotations


 Interfaces: Define contracts for objects, ensuring consistency and
reusability.
 Advanced Annotations: Include union types, intersection types,
optional properties, and more.
 Example:
 interface User {
 id: number;
 name: string;
 email?: string; // Optional
 }
 function displayUser(user: User): void {
 console.log(`ID: ${user.id}, Name: ${user.name}`);}
2.1.4 Utility Types (Mapped Types, Conditional Types)
 Mapped Types: Transform existing types into new ones.
o Example: Partial<T> makes all properties optional.
 interface User {
 id: number;
 name: string;
 }
 const user: Partial<User> = { name: 'Alice' }; // `id` is optional
 Conditional Types: Apply logic based on conditions.
o Example:
 type IsString<T> = T extends string ? true : false;
 type Result = IsString<'Hello'>; // true

2.2 Building a Type-Safe Angular Application


2.2.1 Leveraging TypeScript to Enforce Data Types
 TypeScript ensures type safety across all parts of an Angular
application, including components, services, and templates.
 Example:
 @Component({
 selector: 'app-user',
 template: '<p>{{ user.name }}</p>'
 })
 export class UserComponent {
 user: { id: number; name: string } = { id: 1, name: 'Alice' };
 }
2.2.2 Using Interfaces to Define Contracts
 Interfaces act as blueprints for objects, enforcing structure and type-
checking.
 Commonly used to define the shape of data exchanged between
components or APIs.
 Example:
 interface Product {
 id: number;
 name: string;
 price: number;
 }

 @Injectable({ providedIn: 'root' })


 export class ProductService {
 getProducts(): Product[] {
 return [
 { id: 1, name: 'Laptop', price: 1000 },
 { id: 2, name: 'Mouse', price: 50 },
 ];
 }
 }

2.2.3 Writing Unit Tests with Type Safety


 TypeScript ensures tests align with the application’s structure,
preventing mismatches.
 Example using Jasmine:
 describe('ProductService', () => {
 let service: ProductService;
 beforeEach(() => {
 service = new ProductService();
 });

 it('should return a list of products', () => {


 const products: Product[] = service.getProducts();
 expect(products.length).toBeGreaterThan(0);
 });
 });
3) Mastering Node.js and Express.js

3 Mastering Node.js and Express.js


Node.js and Express.js are foundational technologies for modern backend
development. Node.js is a runtime for running JavaScript server-side, while
Express.js is a lightweight framework for building robust APIs.

3.1 Node.js in Depth

3.1.1 Asynchronous Programming with Promises and Async/Await


 Asynchronous Programming: Handles tasks (e.g., I/O operations)
without blocking the execution of other tasks.
 Promises: Represents a value that will be resolved or rejected in the
future.
o Example:
const fetchData = () => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve('Data fetched'), 1000);
});
};
fetchData().then(console.log).catch(console.error);
 Async/Await: Syntactic sugar over promises, making asynchronous
code easier to read.
o Example:
const fetchData = async () => {
try {
const data = await fetchDataFromAPI();
console.log(data);
} catch (error) {
console.error(error);
}
};
fetchData();

3.1.2 Event Loop and Non-Blocking I/O


 Event Loop: Core of Node.js that handles asynchronous operations.
It allows non-blocking execution of I/O tasks by delegating them to
system threads.
 Phases: Timers, Pending Callbacks, Poll, Check, and Close
Callbacks.
 Non-Blocking I/O: Node.js uses the libuv library to offload I/O
operations, ensuring that the main thread remains free to handle
other tasks.
o Example:
console.log('Start');
setTimeout(() => console.log('Timeout'), 0);
console.log('End');
// Output: Start -> End -> Timeout

3.1.3 Modules and the Node.js Package Manager (npm)


 Modules: Reusable chunks of code, organized into files. Three
types:
1. Core Modules: Built into Node.js (e.g., fs, http, path).
2. Local Modules: Custom modules created by developers.
3. Third-Party Modules: Installed via npm.
 npm: Default package manager for Node.js.
o Example:
o npm install express
o Add functionality by importing modules:
o const express = require('express');
3.2 Building a RESTful API with Express.js

3.2.1 Creating Routes for Handling HTTP Requests


 Define routes to manage various HTTP methods (GET, POST, PUT,
DELETE).
 Example:
const express = require('express');
const app = express();

app.get('/users', (req, res) => res.send('Get all users'));


app.post('/users', (req, res) => res.send('Create a user'));
app.put('/users/:id', (req, res) => res.send(`Update user with ID:
${req.params.id}`));
app.delete('/users/:id', (req, res) => res.send(`Delete user with ID:
${req.params.id}`));

app.listen(3000, () => console.log('Server running on port 3000'));

3.2.2 Middleware for Request Processing and Error Handling


 Middleware: Functions executed during the request-response cycle.
 Types:
o Built-in (e.g., express.json() for parsing JSON).
o Third-party (e.g., cors, morgan).
o Custom Middleware.
 Example:
app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
});
app.use((err, req, res, next) => {
res.status(500).send({ error: err.message });
});

3.2.3 Body Parsing and Validation


 Use middleware to parse and validate incoming request data.
 Example with express.json() for parsing and Joi for validation:
const Joi = require('joi');

app.use(express.json());

app.post('/users', (req, res) => {


const schema = Joi.object({
name: Joi.string().min(3).required(),
email: Joi.string().email().required(),
});
const { error } = schema.validate(req.body);
if (error) return res.status(400).send(error.details[0].message);

res.send('User is valid');
});

3.2.4 Sending JSON Responses


 Express Response API: Provides res.json() to send JSON-
formatted data.
 Example:
app.get('/users', (req, res) => {
const users = [{ id: 1, name: 'John' }, { id: 2, name: 'Doe' }];
res.json(users);
});
4) MongoDB for Data Persistence

4 MongoDB for Data Persistence


MongoDB is a popular NoSQL database known for its flexibility, scalability,
and ease of use. Mongoose, an ODM (Object Data Modeling) library for
MongoDB, adds a structured schema layer to MongoDB, which is schema-
less by default.

4.1 Advanced Mongoose Features


4.1.1 Schema Validation and Middleware
 Schema Validation: Ensures data integrity by defining rules
directly in Mongoose schemas.
o Example:
const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({


name: { type: String, required: true, minlength: 3 },
email: { type: String, required: true, unique: true },
age: { type: Number, min: 18 },
});

const User = mongoose.model('User', userSchema);


 Middleware: Functions that are executed before or after a certain
event in Mongoose (e.g., save, update, delete).
o Example:
userSchema.pre('save', function (next) {
console.log('Before saving user:', this);
next();
});
4.1.2 Population, Aggregation Pipelines, and Custom Queries
 Population: Automatically replaces references in documents with
actual data from other collections.
o Example:
const postSchema = new mongoose.Schema({
title: String,
author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
});

const Post = mongoose.model('Post', postSchema);

Post.find().populate('author').exec((err, posts) => {


console.log(posts);
});
 Aggregation Pipelines: Process data through stages like $match,
$group, and $project for analytics.
o Example:
Post.aggregate([
{ $match: { author: 'John' } },
{ $group: { _id: '$author', totalPosts: { $sum: 1 } } },
]).exec(console.log);
 Custom Queries: Define reusable query methods for advanced
filtering or sorting.
o Example:
userSchema.query.byName = function (name) {
return this.where({ name: new RegExp(name, 'i') });
};

User.find().byName('Alice').exec(console.log);
4.1.3 Mongoose with TypeScript for Type Safety
 Integrating TypeScript provides stronger type safety and better
tooling for Mongoose models.
o Example:
import { Schema, model, Document } from 'mongoose';

interface IUser extends Document {


name: string;
email: string;
}

const userSchema = new Schema<IUser>({


name: { type: String, required: true },
email: { type: String, required: true },
});

const User = model<IUser>('User', userSchema);

4.2 Database Authentication and Security


4.2.1 User Authentication and Authorization
 Authentication: Verifies user identity using methods like tokens
(JWT), session cookies, etc.
 Authorization: Controls user access to resources based on roles or
permissions.
o Example: Adding user roles in a schema:
const userSchema = new mongoose.Schema({
role: { type: String, enum: ['admin', 'user'], default: 'user' },
});
4.2.2 Data Encryption at Rest and in Transit
 Encryption at Rest: Ensures data is encrypted on disk using
mechanisms like MongoDB’s encrypted storage engine.
 Encryption in Transit: Secures data with SSL/TLS when
transmitted between the database and clients.
o Example: Enabling TLS in MongoDB:
mongod --tlsMode requireTLS --tlsCertificateKeyFile
/path/to/cert.pem

4.2.3 Best Practices for Secure MongoDB Deployments


1. Use strong, unique passwords and authentication mechanisms.
2. Restrict access using IP whitelisting or firewalls.
3. Enable SSL/TLS for encrypted communication.
4. Regularly update MongoDB to patch vulnerabilities.
5. Backup data and test recovery processes.

4.3 Scalability and High Availability


4.3.1 Sharding for Horizontal Scaling
 Sharding: Distributes data across multiple servers for horizontal
scalability.
o Example: Configuring a shard key in MongoDB.
sh.shardCollection("database.collection", { shardKey: 1 })

4.3.2 Replication for Data Redundancy and Failover


 Replication: Copies data across multiple servers to ensure
redundancy and improve availability.
 Primary server handles writes; secondary servers replicate data.
 Failover ensures automatic switching to a secondary server if the
primary fails.
4.3.3 MongoDB Atlas for Managed Database Services
 MongoDB Atlas: A cloud-based managed database service for
MongoDB.
o Benefits: Automatic backups, monitoring, scaling, and
security.
o Example: Configuring clusters via Atlas UI or CLI.
5) Advanced Topics and Best Practices

5.1 Performance Optimization Techniques


5.1.1 Code Splitting and Lazy Loading for Faster Initial Load Times
 Code Splitting: Divides the application code into smaller bundles
that are loaded on demand, reducing the initial load time.
o Example with Webpack:
o import(/* webpackChunkName: "module" */
'./module').then(module => {
o module.doSomething();
o });
 Lazy Loading in Angular: Loads modules only when needed.
o Example:
o const routes = [
o {
o path: 'feature',
o loadChildren: () =>
import('./feature/feature.module').then(m =>
m.FeatureModule),
o },
o ];

5.1.2 Change Detection Strategies (OnPush)


 Default Strategy: Checks all components in the tree when a change
occurs.
 OnPush Strategy: Limits change detection to the component and
its inputs, improving performance.
o Example:
@Component({
selector: 'app-example',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `<div>{{ data }}</div>`,
})
export class ExampleComponent {
@Input() data!: string;
}

5.1.3 Caching Mechanisms (Local Storage, Service Workers)


 Local Storage: Stores key-value pairs for offline access.
o Example:
o localStorage.setItem('user', JSON.stringify({ name: 'John' }));
o const user = JSON.parse(localStorage.getItem('user')!);
 Service Workers: Cache application resources for offline use.
o Example with Workbox:
o workbox.routing.registerRoute(
o ({ request }) => request.destination === 'image',
o new workbox.strategies.CacheFirst()
o );

5.2 Security Considerations


5.2.1 Cross-Site Scripting (XSS) and Cross-Site Request Forgery (CSRF)
Prevention
 XSS Prevention: Protects against malicious scripts injected into the
application.
o Techniques:
 Use Angular’s built-in template sanitization.
 Escape user input in templates.
 Example:
 const safeInput = DOMPurify.sanitize(userInput);
 CSRF Prevention: Prevents unauthorized actions on behalf of
authenticated users.
o Use anti-CSRF tokens.
o Example with Express.js:
o const csrf = require('csurf');
o app.use(csrf());

5.2.2 Input Validation and Sanitization


 Validate and sanitize all user inputs to prevent injection attacks.
o Example with Joi:
o const schema = Joi.object({
o username:
Joi.string().alphanum().min(3).max(30).required(),
o });
o

o const { error } = schema.validate(req.body);


o if (error) return res.status(400).send(error.details[0].message);

5.2.3 Secure Communication with the Backend (HTTPS)


 Use HTTPS for encrypting communication between the client and
server.
 Enable SSL/TLS in server configurations.
o Example with Express.js:
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.cert'),
};
https.createServer(options, app).listen(443);
5.3 Testing Strategies
5.3.1 Unit Testing with Jest or Karma
 Unit Testing: Tests individual components, services, or functions in
isolation.
 Example with Jest:
describe('add function', () => {
it('should add two numbers', () => {
expect(add(2, 3)).toBe(5);
});
});

5.3.2 End-to-End Testing with Cypress or Playwright


 End-to-End Testing: Simulates user interactions with the
application to test workflows.
 Example with Cypress:
describe('Login Page', () => {
it('should log in the user', () => {
cy.visit('/login');
cy.get('input[name="username"]').type('testuser');
cy.get('input[name="password"]').type('password');
cy.get('button[type="submit"]').click();
cy.url().should('include', '/dashboard');
});
});
5.3.3 Best Practices for Writing Effective Tests
1. Keep tests isolated and deterministic.
2. Mock external dependencies.
3. Use meaningful test names.
4. Write tests for edge cases.
5. Continuously integrate tests into the development pipeline.

You might also like