This repository contains a list of resources to learn Angular. It includes tutorials, articles, videos, books, and other resources to help you learn Angular from scratch.
- Introduction
- Roadmap
- Configuration
- Components
- Data Binding
- Directives
- Pipes
- Decorators
- Life Cycle Hooks
- Forms
- Services
- Routing
- Lazy Loading
- HTTP Client
- Destroy Ref
- Http
- Module
- Router
- Route Parameter
- Observables
- Unsubscribe
- Renderer2
- JIT
- AOT
- Deferrable Views
- Meta Tags
- Security
- Preventing cross-site scripting (XSS)
- Angular's cross-site scripting security model
- Preventing cross-site scripting (XSS)
- Angular's cross-site scripting security model
- Sanitization and security contexts
- Sanitization example
- Direct use of the DOM APIs and explicit sanitization calls
- Trusting safe values
- Content security policy
- Enforcing Trusted Types
- Use the AOT template compiler
- Server-side XSS protection
- HTTP-level vulnerabilities
- Cross-site request forgery
- HttpClient XSRF/CSRF security
- Configure custom cookie/header names
- Disabling XSRF protection
- Cross-site script inclusion (XSSI)
- Auditing Angular applications
- Standalone Components
- Angular Signals
- Angular Animations
- Angular Universal
- Bootstrap
- Angular Material
- Tailwind CSS
- PrimeNG
- PWA
- CLI Commands
- Version compatibility
- Imports
- TypeScript
- RxJS
- Learn From GitHub Repositories
- Learn From Websites
- Learn From Books
- Learn From YouTube Channels
- Learn More From Blogs Sites
- List of Online Editors/Compiler for Angular
- List of Twitter Users to Follow
- List of LinkedIn Users to Follow
- List of Discord Servers to Join
Angular is a popular open-source web application framework developed by Google. It is used for building single-page web applications and dynamic web applications. Angular provides a set of tools and libraries for building modern web applications, including components, services, forms, routing, HTTP client, and more. Angular is built using TypeScript, a superset of JavaScript that adds static typing and other features to the language. Angular is known for its performance, scalability, and developer productivity.
-
Component-Based Architecture - Angular is based on a component-based architecture, where components are the main building blocks of an application. Components are reusable, self-contained units of code that define the UI and behavior of a part of the application.
-
Two-Way Data Binding - Angular provides two-way data binding, which allows for automatic synchronization of data between the model and the view. This means that changes to the model are reflected in the view, and changes to the view are reflected in the model.
-
Dependency Injection - Angular uses dependency injection to provide components with the services they need. This allows for better modularity, testability, and reusability of code.
-
Routing - Angular provides a powerful routing system that allows for navigation between different views of an application. Routing is based on the URL of the application and allows for deep linking, lazy loading, and route guards.
-
Forms - Angular provides a rich set of tools for working with forms, including template-driven forms and reactive forms. Forms in Angular are based on the model-driven approach, where the form controls are bound to properties in the component's class.
-
HTTP Client - Angular provides an HTTP client module that allows for making HTTP requests to a server. The HTTP client module provides a simple API for working with RESTful APIs and handling responses.
-
Observables - Angular uses observables to handle asynchronous operations, such as HTTP requests and event handling. Observables are a powerful way to work with asynchronous data streams and provide a consistent way to handle events in an application.
-
TypeScript - Angular is built using TypeScript, a superset of JavaScript that adds static typing and other features to the language. TypeScript provides better tooling, error checking, and code completion, which makes it easier to build and maintain large applications.
-
Performance - Angular is designed for performance and scalability. It uses a virtual DOM to optimize rendering performance, and provides tools for lazy loading, tree shaking, and ahead-of-time compilation to reduce the size of the application and improve performance.
-
Mobile Support - Angular provides tools for building mobile applications, including responsive design, touch gestures, and mobile-specific features. Angular applications can be built as Progressive Web Apps (PWAs) and deployed to mobile devices using Cordova or Capacitor.
-
SEO Friendly - Angular provides tools for building SEO-friendly applications, including server-side rendering, pre-rendering, and meta tags. Angular applications can be optimized for search engines to improve visibility and ranking in search results.
-
Community Support - Angular has a large and active community of developers, who contribute to the framework, provide support, and share knowledge through blogs, forums, and social media. The Angular community is known for its helpfulness, inclusivity, and diversity.
AngularJS | Angular |
---|---|
Based on MVC Architecture | Based on Components |
Uses JavaScript to build the application | Uses TypeScript to build the application |
No Mobile Support | Mobile supports |
Run on only client-side | Runs on both client-side as well as server-side |
CLI not present | CLI present |
No SEO Friendly | Seo Friendly |
Performance is slow | Performance is fast |
-
Angular - Angular is a full-fledged framework that provides a complete solution for building web applications. It includes features like two-way data binding, routing, forms, HTTP client, and more. Angular is maintained by Google and has a large and active community of developers.
-
React - React is a JavaScript library for building user interfaces. It is focused on the view layer of an application and provides a simple and declarative way to build UI components. React is maintained by Facebook and has a large and active community of developers.
Comparison - Angular is a full-fledged framework that provides a complete solution for building web applications, while React is a library focused on building user interfaces. Angular provides features like two-way data binding, routing, forms, and HTTP client out of the box, while React is more flexible and allows developers to choose the tools and libraries they want to use.
When to use Angular - Angular is a good choice for building large and complex web applications that require a complete solution for building UI components, managing state, and handling data. Angular provides a set of tools and libraries that work well together and are designed to scale with the size of the application.
When to use React - React is a good choice for building user interfaces that are focused on the view layer of an application. React provides a simple and declarative way to build UI components and allows developers to choose the tools and libraries they want to use. React is a good choice for building small to medium-sized applications that require flexibility and customization.
SPA stands for Single Page Application. It is a web application or website that interacts with the user by dynamically rewriting the current page rather than loading entire new pages from the server. This approach allows for a more fluid and responsive user experience, as the page does not need to be reloaded each time the user interacts with it.
-
Faster Load Times - SPAs load faster than traditional web applications because they only need to load the initial page once. Subsequent interactions with the application can be handled by updating the current page dynamically.
-
Better User Experience - SPAs provide a more fluid and responsive user experience because they do not need to reload the entire page each time the user interacts with it. This allows for faster navigation and smoother transitions between pages.
-
Reduced Server Load - SPAs reduce the load on the server because they do not need to fetch and render entire new pages each time the user interacts with the application. This can lead to cost savings and improved performance.
-
Improved SEO - SPAs can be optimized for search engines by using server-side rendering, pre-rendering, and meta tags. This allows search engines to index the content of the application and improve its visibility in search results.
-
Offline Support - SPAs can provide offline support by using service workers and caching strategies. This allows users to access the application even when they are offline or have a slow internet connection.
-
Mobile Support - SPAs can be optimized for mobile devices by using responsive design, touch gestures, and mobile-specific features. This allows the application to work well on a wide range of devices and screen sizes.
-
Scalability - SPAs are scalable and can handle a large number of users and interactions. They can be optimized for performance by using lazy loading, tree shaking, and ahead-of-time compilation to reduce the size of the application and improve performance.
- Node.js
Install the Angular CLI globally:
npm install -g @angular/cli
Check version
ng version
Create workspace:
# with standalone component
ng new [PROJECT NAME]
# without standalone component
ng new [PROJECT NAME] --standalone=false
Note: In version v17 and later, the standalone component is default enabled. In version v16 and earlier, the standalone component is disabled by default. You can enable or disable the standalone component using the --standalone
flag.
Navigate to the project directory:
cd [PROJECT NAME]
Run the application:
ng serve
Open the browser and navigate to http://localhost:4200/
.
Component is the main building block of an Angular Application. It is a TypeScript class that interacts with the HTML template and provides the data and logic to the view.
There are three main building blocks of an Angular component:
- Template
- Class
- Metadata
Template - Defines the layout and content of the View.
Class - Class provides the data & logic to the View.
MetaData - Metadata Provides additional information about the component to the Angular.
There are several properties that can be defined in the component metadata:
- Selector
- Providers
- Styles
- StyleUrls
- Template
- TemplateUrl
Selector - Defines the element name or CSS selector that identifies the component in the HTML template.
Providers - Defines the providers of the component's dependencies.
styles - Defines the inline styles for the component.
styleUrls - Defines an array of URLs of the stylesheets for the component.
template - Defines the HTML template for the component.
templateUrl - Defines the URL of the HTML template for the component.
ng generate component [component-name]
Step 1 - Create a new folder for the component inside the src/app
folder.
src/app/[component-name]
Step 2 - Create a new TypeScript file for the component inside the new folder.
src/app/[component-name]/[component-name].component.ts
Step 3 - Create a new HTML file for the component inside the new folder.
src/app/[component-name]/[component-name].component.html
Step 4 - Create a new CSS file for the component inside the new folder.
src/app/[component-name]/[component-name].component.css
Step 5 - Import the Component class from the @angular/core
module.
import { Component } from '@angular/core';
Step 6 - Decorate the class with the @Component
decorator.
@Component({
selector: 'app-[component-name]',
templateUrl: './[component-name].component.html',
styleUrls: ['./[component-name].component.css']
})
Step 7 - Define the selector, template, and styles for the component.
selector - The selector for the component.
templateUrl - The URL of the HTML template for the component.
styleUrls - An array of URLs of the stylesheets for the component.
Step 8 - Export the class.
export class [ComponentName]Component {
}
Step 9 - Import the component class in the app.module.ts
file.
import { [ComponentName]Component } from './[component-name]/[component-name].component';
Step 10 - Add the component to the declarations
array in the @NgModule
decorator.
declarations: [
AppComponent,
[ComponentName]Component
]
Step 11 - Use the component selector in the HTML template of the app.component.ts
file.
<app-[component-name]></app-[component-name]>
Step 12 - Run the application using the ng serve
command.
ng serve
Creating the component files -
//test-component.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'test-component',
templateUrl: './component.component.html',
styleUrls: ['./component.component.css']
})
export class TestComponent {
}
<!--component.component.html-->
<h1>Test Component</h1>
/*component.component.css*/
h1 {
color: red;
}
Importing the component in the app.module.ts file -
//app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { TestComponent } from './app.component';
@NgModule({
declarations: [
AppComponent,
TestComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Creating the inline Template & StyleUrls -
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: '<h1> {{title}} works </h1>',
styles: ['h1 { font-weight: bold; }']
})
export class AppComponent {
title = 'app';
}
The scope of a variable in Angular refers to the context in which the variable is defined and can be accessed. There are three main types of scope in Angular:
-
Global Scope - Variables defined in the global scope are accessible from anywhere in the application. They are defined outside of any function or block of code.
-
Local Scope - Variables defined in a function or block of code are accessible only within that function or block. They are not accessible outside of the function or block.
-
Component Scope - Variables defined in an Angular component are accessible within that component and its child components. They are not accessible outside of the component.
Variables defined in the global scope are accessible from anywhere in the application. They are defined outside of any function or block of code.
Example :
// Global Scope
let globalVariable = 'Global Variable';
function testFunction() {
console.log(globalVariable); // Output: Global Variable
}
testFunction();
Variables defined in a function or block of code are accessible only within that function or block. They are not accessible outside of the function or block.
Example :
function testFunction() {
// Local Scope
let localVariable = 'Local Variable';
console.log(localVariable); // Output: Local Variable
}
testFunction();
console.log(localVariable); // Error: localVariable is not defined
Variables defined in an Angular component are accessible within that component and its child components. They are not accessible outside of the component.
Example :
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
// Component Scope
title = 'app';
}
<!--app.component.html-->
<h1>{{ title }}</h1>
View Encapsulation is a feature of Angular that allows you to control how styles are applied to components. By default, Angular uses Emulated View Encapsulation, which means that styles are scoped to the component and do not affect other components.
Emulated View Encapsulation is the default mode in Angular. In this mode, Angular emulates the shadow DOM to apply styles to components. This means that styles are scoped to the component and do not affect other components.
import { Component, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
encapsulation: ViewEncapsulation.Emulated
})
export class AppComponent {
title = 'app';
}
Shadow DOM View Encapsulation uses the native shadow DOM to apply styles to components. This means that styles are encapsulated within the shadow DOM and do not affect other components.
import { Component, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
encapsulation: ViewEncapsulation.ShadowDom
})
export class AppComponent {
title = 'app';
}
None View Encapsulation disables view encapsulation for the component. This means that styles are not scoped to the component and can affect other components.
import { Component, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
title = 'app';
}
Component communication is the process of passing data between components in an Angular application. There are several ways to achieve component communication in Angular, including Input and Output decorators, EventEmitter, and services.
Input Decorator - The @Input
decorator is used to pass data from a parent component to a child component. It allows the parent component to bind a property to the child component.
Example :
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css']
})
export class ChildComponent {
@Input() message: string;
}
<!--child.component.html-->
<p>{{ message }}</p>
import { Component } from '@angular/core';
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css']
})
export class ParentComponent {
message = 'Hello from parent component';
}
<!--parent.component.html-->
<app-child [message]="message"></app-child>
Output Decorator - The @Output
decorator is used to pass data from a child component to a parent component. It allows the child component to emit events that the parent component can listen to.
Example :
import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css']
})
export class ChildComponent {
@Output() messageEvent = new EventEmitter<string>();
sendMessage() {
this.messageEvent.emit('Hello from child component');
}
}
<!--child.component.html-->
<button (click)="sendMessage()">Send Message</button>
import { Component } from '@angular/core';
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css']
})
export class ParentComponent {
message: string;
receiveMessage($event) {
this.message = $event;
}
}
<!--parent.component.html-->
<app-child (messageEvent)="receiveMessage($event)"></app-child>
<p>{{ message }}</p>
Data binding is a core feature of Angular that allows you to bind data between the component's class and the HTML template. There are two types of data binding in Angular:
There are two types of data binding in Angular:
-
One-way binding - This allows for passing data from the component's class to the HTML template or vice-versa.
-
Two-way binding - This allows for binding a property of an HTML element to a property in the component's class and vice-versa.
One-way binding allows for passing data from the component's class to the HTML template.
There are several ways to achieve one-way binding in Angular, including:
- From Component to View
- From View to Component
1. From Component to View - This allows for passing data from the component's class to the HTML template.
There are several ways to achieve one-way binding from the component to the view in Angular, including:
- Interpolation
- Property binding
- Class binding
- Style binding
- Attribute binding
Interpolation - This allows for embedding expressions in the HTML template. It is denoted by double curly braces ({{}}).
Example :
<h1>{{ firstText }} {{ lastText }}</h1>
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
firstText = 'Interpolation';
lastText = 'Example';
}
Property binding - This allows for binding a property of an HTML element to a property in the component's class. It is denoted by square brackets ([]).
Example :
<h1 [innerText]="title"></h1>
<button [disabled]="isDisabled">I am disabled</button>
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
title = 'Angular Property Binding Example';
isDisabled = true;
}
class binding - This allows for binding a class of an HTML element to a property in the component's class. It is denoted by square brackets ([]).
Example :
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
isActive = false;
toggleActive() {
this.isActive = !this.isActive;
}
}
<div [class.active]="isActive">This div is active.</div>
<button (click)="toggleActive()">Toggle Active</button>
.active {
background-color: yellow;
}
style binding - This allows for binding a style of an HTML element to a property in the component's class. It is denoted by square brackets ([]).
Example :
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
backgroundColor = 'red';
textColor = 'white';
}
<div [style.background-color]="backgroundColor">
<h1 [style.color]="textColor">Hello, world!</h1>
</div>
attribute binding - This allows for binding an attribute of an HTML element to a property in the component's class. It is denoted by square brackets ([]).
Example :
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
imageUrl = 'https://example.com/image.jpg';
imageAlt = 'Example image';
isButtonDisabled = false;
}
<img [attr.src]="imageUrl" [attr.alt]="imageAlt">
<button [attr.disabled]="isButtonDisabled">Click me</button>
b. From View to Component - This allows for passing data from the HTML template to the component's class.
There are several ways to achieve one-way binding from the view to the component in Angular, including:
- Event binding
- ngModel
Event binding - This allows for binding an event of an HTML element to a method in the component's class. It is denoted by parentheses (()).
Example :
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
onClick() {
console.log('Button was clicked');
}
}
<h1>Event Binding Example</h1>
<button (click)="onClick()">Click me</button>
ngModel - The ngModel
directive is used to create two-way data binding between an input element and a property in the component's class. It is commonly used to bind form controls to properties in the component.
Example :
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
name: string = '';
}
<input [(ngModel)]="name" placeholder="Enter your name">
<p>Your name is: {{name}}</p>
Remeber💡 :
The (click) calls the specified function when a user clicks on the given element (in your example, when a user clicks on a row).
The (change) event binds to HTML's onChange event. This event is fired for <input>
, <select>
, and <textarea>
elements when a change to the element's value is committed by the user.
The (change) event can also be specifically implemented by other Angular components. It is generally implemented on components where the contents of the component are changed by the user.
Two-way binding allows for binding a property of an HTML element to a property in the component's class and vice-versa. It is denoted by [(ngModel)]
.
There are several ways to achieve two-way binding in Angular, including:
- ngModel
- ngModelChange
- change event
ngModel - The ngModel
directive is used to create two-way data binding between an input element and a property in the component's class. It is commonly used to bind form controls to properties in the component.
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
name: string = '';
}
<input [(ngModel)]="name" placeholder="Enter your name">
<p>Your name is: {{name}}</p>
ngModelChange - The ngModelChange
event is emitted when the value of an input element bound to ngModel
changes. It can be used to perform additional logic when the value changes.
Example :
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
name: string = '';
onNameChange(value: string) {
console.log('Name changed to:', value);
}
}
<input [(ngModel)]="name" (ngModelChange)="onNameChange($event)" placeholder="Enter your name">
<p>Your name is: {{name}}</p>
change event - The change
event is emitted when the value of an input element changes. It can be used to perform additional logic when the value changes.
Example :
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
name: string = '';
onNameChange(value: string) {
console.log('Name changed to:', value);
}
}
<input [(ngModel)]="name" (change)="onNameChange($event.target.value)" placeholder="Enter your name">
<p>Your name is: {{name}}</p>
Directives add behaviour to an existing DOM element or an existing component instance.
There are three types of directives in Angular:
-
Structural Directives - Structural directives are used to add or remove elements from the DOM based on a condition. They are denoted by an asterisk (*) before the directive name.
-
Attribute Directives - Attribute directives are used to change the appearance or behavior of an element. They are denoted by square brackets [] before the directive name.
-
Custom Directives - Custom directives are user-defined directives that add custom behavior to an element. They can be used to encapsulate complex behavior and reuse it across multiple components.
There are several built-in structural directives in Angular, including:
- NgIf
- NgFor
- NgSwitch
ngIf - The ngIf
directive is used to conditionally display elements based on the value of a given expression. It is commonly used to show or hide elements in the UI based on certain conditions.
Example :
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
showElement = true;
}
<h1>ngIf Example</h1>
<div *ngIf="showElement">
This element will only be displayed if showElement is true.
</div>
ngFor - The ngFor
directive is used to iterate over a list of items and create a template for each item. It is commonly used to display a list of items in the UI.
Example :
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
items = ['Item 1', 'Item 2', 'Item 3'];
}
<h1>ngFor Example</h1>
<ul>
<li *ngFor="let item of items">{{ item }}</li>
</ul>
ngSwitch - The ngSwitch
directive is used to conditionally display elements based on the value of a given expression. It is similar to a switch statement in JavaScript.
Example :
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
value = 1;
}
<h1>ngSwitch Example</h1>
<div [ngSwitch]="value">
<div *ngSwitchCase="1">Case 1</div>
<div *ngSwitchCase="2">Case 2</div>
<div *ngSwitchCase="3">Case 3</div>
<div *ngSwitchDefault>Default case</div>
</div>
There are several built-in attribute directives in Angular, including:
- NgClass
- NgStyle
- NgModel
ngClass - The ngClass
directive is used to conditionally apply CSS classes to an element based on the value of a given expression. It is commonly used to apply styles to elements based on certain conditions.
Example :
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
isHighlighted = true;
}
<h1>ngClass Example</h1>
<div [ngClass]="{ highlighted: isHighlighted }">
This element will have the 'highlighted' class if isHighlighted is true.
</div>
.highlighted {
background-color: yellow;
}
ngStyle - The ngStyle
directive is used to conditionally apply inline styles to an element based on the value of a given expression. It is commonly used to apply dynamic styles to elements based on certain conditions.
Example :
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
color = 'red';
}
<h1>ngStyle Example</h1>
<div [ngStyle]="{ color: color }">
This element will have the color style set to the value of the color property.
</div>
ngModel - The ngModel
directive is used to create two-way data binding between an input element and a property in the component's class. It is commonly used to bind form controls to properties in the component.
Example :
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
name: string;
}
<h1>ngModel Example</h1>
<form>
<label for="name">Name:</label>
<input type="text" id="name" [(ngModel)]="name" name="name" />
</form>
Custom directives are user-defined directives that add custom behavior to an element. They can be used to encapsulate complex behavior and reuse it across multiple components.
Example :
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
@Directive({
selector: '[appCustomDirective]',
})
export class CustomDirectiveDirective {
constructor(private el: ElementRef) {}
@HostListener('mouseenter') onMouseEnter() {
this.highlight('yellow');
}
@HostListener('mouseleave') onMouseLeave() {
this.highlight(null);
}
private highlight(color: string) {
this.el.nativeElement.style.backgroundColor = color;
}
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { CustomDirectiveDirective } from './custom-directive.directive';
@NgModule({
imports: [BrowserModule, FormsModule],
declarations: [AppComponent, CustomDirectiveDirective],
bootstrap: [AppComponent],
})
export class AppModule {}
<h1>Custom Directive Element</h1>
<div appCustomDirective>
This element will have a yellow background when the mouse is over it.
</div>
There are several other built-in directives in Angular, including:
- ngContainer
- ngTemplate
- ngContent
- ngTemplateOutlet
ngContainer - The ngContainer
directive is a simple container that doesn't generate any markup in the DOM. It's mainly used as a placeholder to group and structure content within Angular templates.
Example :
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
condition = true;
}
<h1>ngContainer Example</h1>
<div *ngIf="condition">
<ng-container>
<p>Content to be conditionally rendered</p>
<p>More content...</p>
</ng-container>
</div>
ngTemplate - The ngTemplate
directive is used to define a reusable template block that can be used later within the same component or shared across components using the ngTemplateOutlet directive.
Example :
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
selectedTemplate: any;
}
<h1>ngTemplate Example</h1>
<ng-template #myTemplate>
<p>This is a template</p>
<p>It can be reused in multiple places</p>
</ng-template>
<div>
<ng-container *ngTemplateOutlet="selectedTemplate"></ng-container>
</div>
<button (click)="selectedTemplate = myTemplate">Load Template</button>
ngContent - The ngContent
directive is used for content projection or transclusion. It allows you to create reusable components with customizable content.
Example :
import { Component } from '@angular/core';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css'],
})
export class ChildComponent {}
import { Component } from '@angular/core';
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css'],
})
export class ParentComponent {}
<!-- Parent Component -->
<app-child>
<p>Content projected into the child component</p>
</app-child>
<!-- Child Component Template -->
<div>
<ng-content></ng-content>
</div>
ngTemplateOutlet - The ngTemplateOutlet
directive is used to render a template defined using ngTemplate. It allows you to dynamically render a template within a component's template.
Example :
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
selectedTemplate: any;
}
<h1>ngTemplateOutlet Example</h1>
<ng-container *ngTemplateOutlet="selectedTemplate"></ng-container>
<ng-template #template1>
Template 1 content
</ng-template>
<ng-template #template2>
Template 2 content
</ng-template>
<button (click)="selectedTemplate = template1">Load Template 1</button>
<button (click)="selectedTemplate = template2">Load Template 2</button>
A pipe takes in data as input and transforms it to a desired output.
Syntax:
{{ data | pipe }}
Expression | pipeOperator[:pipeArguments]
# Expression: is the expression, which you want to transform
# | : is the Pipe Character
# pipeOperator : name of the Pipe
# pipeArguments: arguments to the Pipe
There are several built-in pipes in Angular, including:
- Date Pipe
- Uppercase Pipe
- Lowercase Pipe
- Currency Pipe
- Percent Pipe
- Slice Pipe
- Decimal/number Pipe
- JSON Pipe
- Async Pipe
The date
pipe is used to format a date value according to the locale rules specified in the application.
import { DatePipe } from '@angular/common';
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
date = new Date();
constructor(private datePipe: DatePipe) {}
formatDate() {
return this.datePipe.transform(this.date, 'shortDate');
}
}
<h1>Date Pipe Example</h1>
<p>{{ date | date: 'shortDate' }}</p>
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { DatePipe } from '@angular/common';
@NgModule({
imports: [BrowserModule, FormsModule],
declarations: [AppComponent],
bootstrap: [AppComponent],
providers: [DatePipe],
})
export class AppModule {}
The uppercase
pipe is used to transform a string to uppercase.
<h1>Upper Case Pipe Example</h1>
<p>{{ name | uppercase }}</p>
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
name = 'Manthan Ank';
}
The lowercase
pipe is used to transform a string to lowercase.
<p>{{ name | lowercase }}</p>
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
name = 'Manthan Ank';
}
The currency
pipe is used to format a number as currency using the locale rules specified in the application.
<h1>Currency Pipe Example</h1>
<p>{{ price | currency }}</p>
import { CurrencyPipe } from '@angular/common';
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
price = 100;
constructor(private currencyPipe: CurrencyPipe) { }
formatCurrency() {
return this.currencyPipe.transform(this.price, 'USD', true);
}
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { CurrencyPipe } from '@angular/common';
@NgModule({
imports: [BrowserModule, FormsModule],
declarations: [AppComponent],
bootstrap: [AppComponent],
providers: [CurrencyPipe],
})
export class AppModule {}
The percent
pipe is used to format a number as a percentage.
<h1>Percent Pipe Example</h1>
<p>{{ percentage | percent }}</p>
import { PercentPipe } from '@angular/common';
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
percentage = 0.5;
constructor(private percentPipe: PercentPipe) {}
formatPercentage() {
return this.percentPipe.transform(this.percentage, '2');
}
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { HelloComponent } from './hello.component';
import { PercentPipe } from '@angular/common';
@NgModule({
imports: [BrowserModule, FormsModule],
declarations: [AppComponent],
bootstrap: [AppComponent],
providers: [PercentPipe],
})
export class AppModule {}
The slice
pipe is used to create a new array or string containing a subset of the elements of the input array or string.
<p>{{ ['apple', 'banana', 'orange', 'mango'] | slice:1:3 }}</p>
The number
pipe is used to format a number as text. It can be used to format a number as a percentage, currency, or decimal number.
<p>{{ 123456.78 | number:'3.2-3' }}</p>
The json
pipe is used to transform a JavaScript object into a JSON string.
<p>{{data | json}}</p>
The async
pipe is used to subscribe to an Observable or Promise and return the latest value it has emitted.
<p>{{data$ | async}}</p>
// DataService.service.ts
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
@Injectable()
export class DataService {
private data$: Observable<string>;
constructor() {
// Simulating an asynchronous data source
this.data$ = of('Hello, async pipe!').pipe(
// Simulating delay
delay(2000)
);
}
getData(): Observable<string> {
return this.data$;
}
}
// ExampleComponent.component.ts
import { Component } from '@angular/core';
import { Observable } from 'rxjs';
import { DataService } from './data.service';
@Component({
selector: 'app-example',
template: '<div>{{ data$ | async }}</div>',
})
export class ExampleComponent {
data$: Observable<string>;
constructor(private dataService: DataService) {
this.data$ = this.dataService.getData();
}
}
By default, Angular pipes are pure, meaning they are stateless and do not change unless the input value changes. However, you can create impure pipes by setting the pure property to false in the @Pipe decorator.
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'impurePipe',
pure: false,
})
export class ImpurePipe implements PipeTransform {
transform(value: any): any {
return value;
}
}
Decorators are design patterns used to isolate the modification or decoration of a class without modifying the source code.
There are several built-in decorators in Angular, including:
- @Component
- @Directive
- @Injectable
- @Pipe
- @NgModule
- @Input
- @Output
- @HostListener
- @ContentChild
- @ContentChildren
- @ViewChild
- @ViewChildren
The @Component
decorator is used to define a new component in Angular.
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
title = 'My App';
}
<h1>{{ title }}</h1>
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
@NgModule({
imports: [BrowserModule, FormsModule],
declarations: [AppComponent],
bootstrap: [AppComponent],
})
export class AppModule {}
The @Directive
decorator is used to define a new directive in Angular.
import { Directive, ElementRef, HostListener } from '@angular/core';
@Directive({
selector: '[appCustomDirective]',
})
export class CustomDirective {
constructor(private el: ElementRef) {}
@HostListener('mouseenter') onMouseEnter() {
this.highlight('yellow');
}
@HostListener('mouseleave') onMouseLeave() {
this.highlight(null);
}
private highlight(color: string) {
this.el.nativeElement.style.backgroundColor = color;
}
}
<div appCustomDirective>
This element will have a yellow background when the mouse is over it.
</div>
import { NgModule } from '@angular/core';
import { CustomDirective } from './custom.directive';
@NgModule({
declarations: [CustomDirective],
})
export class AppModule {}
The @Injectable
decorator is used to define a new service in Angular.
import { Injectable } from '@angular/core';
@Injectable
export class DataService {
getData() {
return 'Hello, world!';
}
}
import { Component } from '@angular/core';
import { DataService } from './data.service';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
data: string;
constructor(private dataService: DataService) {
this.data = this.dataService.getData();
}
}
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
providers: [DataService],
})
export class AppModule {}
The @Pipe
decorator is used to define a new pipe in Angular.
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'customPipe',
})
export class CustomPipe implements PipeTransform {
transform(value: any, args?: any): any {
return value;
}
}
<h1>{{ data | customPipe }}</h1>
import { NgModule } from '@angular/core';
import { CustomPipe } from './custom.pipe';
@NgModule({
declarations: [CustomPipe],
})
export class AppModule {}
The @NgModule
decorator is used to define a new module in Angular.
import { NgModule } from '@angular/core';
@NgModule({
imports: [],
declarations: [],
providers: [],
bootstrap: [],
})
export class AppModule {}
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
@NgModule({
imports: [BrowserModule, FormsModule],
declarations: [AppComponent],
bootstrap: [AppComponent],
})
export class AppModule {}
The @Input
decorator is used to pass data from a parent component to a child component.
import { Component, Input, OnInit } from '@angular/core';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit {
@Input() message: string;
constructor() { }
ngOnInit() {}
}
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css'],
})
export class ParentComponent implements OnInit {
parentMessage = 'Hello from the parent component!';
constructor() {}
ngOnInit() {}
}
<p>{{ message }}</p>
<app-child [message]="parentMessage"></app-child>
<h1>@Input Example</h1>
<app-parent></app-parent>
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { RouterModule } from '@angular/router';
import { ChildComponent } from './child/child.component';
import { ParentComponent } from './parent/parent.component';
@NgModule({
imports: [BrowserModule, FormsModule, RouterModule],
declarations: [AppComponent, ChildComponent, ParentComponent],
bootstrap: [AppComponent],
})
export class AppModule {}
The @Output
decorator is used to pass data from a child component to a parent component.
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css'],
})
export class ChildComponent implements OnInit {
@Output() messageEvent = new EventEmitter<string>();
constructor() {}
ngOnInit() {}
sendMessage() {
this.messageEvent.emit('Hello from the child component!');
}
}
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css'],
})
export class ParentComponent implements OnInit {
constructor() {}
ngOnInit() {}
handleMessage(message: string) {
console.log(message);
}
}
<button (click)="sendMessage()">Send message</button>
<app-child (messageEvent)="handleMessage($event)"></app-child>
<h1>@Output Decorator Example</h1>
<app-parent></app-parent>
The @HostListener
decorator is used to listen for events on the host element of a directive or component.
<h1>@HostListener Decorator Example</h1>
<p>Click the host element to trigger the 'click' event.</p>
import { Component, HostListener } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
@HostListener('click')
onClick() {
console.log('The host element was clicked!');
}
}
The @ContentChild
and @ContentChildren
decorators are used to query for content children in the component's view.
import {
Component,
ContentChild,
ContentChildren,
ElementRef,
OnInit,
QueryList,
} from '@angular/core';
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css'],
})
export class ParentComponent implements OnInit {
@ContentChild('childButton1', { static: true }) childButton1: ElementRef;
@ContentChildren('childButton2') childButtons2: QueryList<ElementRef>;
ngAfterContentInit() {
console.log(this.childButton1.nativeElement.textContent);
this.childButtons2.forEach((button) => {
console.log(button.nativeElement.textContent);
});
}
constructor() {}
ngOnInit() {}
}
<ng-content></ng-content>
<h1>@ContentChild Decorator Example</h1>
<app-parent></app-parent>
The @ViewChild
and @ViewChildren
decorators are used to query for view children in the component's view.
import { Component, ElementRef, QueryList, ViewChild, ViewChildren } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
@ViewChild('childButton1', { static: true }) childButton1: ElementRef;
@ViewChildren('childButton2') childButtons2: QueryList<ElementRef>;
ngAfterViewInit() {
console.log(this.childButton1.nativeElement.textContent);
this.childButtons2.forEach(button => {
console.log(button.nativeElement.textContent);
});
}
}
<h1>@viewChild & @viewChildren Example</h1>
<button #childButton1>Button 1</button>
<button #childButton2>Button 2</button>
Angular provides a set of lifecycle hooks that give you visibility into key moments in the component's lifecycle.
There are several lifecycle hooks in Angular, including:
- ngOnChanges
- ngOnInit
- ngDoCheck
- ngAfterContentInit
- ngAfterContentChecked
- ngAfterViewInit
- ngAfterViewChecked
- ngOnDestroy
It is called when the data-bound properties of a directive/component are changed. It is called before ngOnInit and whenever one or more data-bound input properties change.
<form>
<input [(ngModel)]="message" name="message" />
<button type="submit" (click)="onSubmit()">Submit</button>
</form>
<p>{{ message }}</p>
import {
Component,
Input,
OnChanges,
OnInit,
SimpleChanges,
} from '@angular/core';
@Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.css'],
})
export class TestComponent implements OnChanges {
@Input() message: string;
prevMessage: string;
ngOnChanges(changes: SimpleChanges) {
if (changes.message) {
console.log(
`message changed from ${changes.message.previousValue} to ${changes.message.currentValue}`
);
}
}
onSubmit() {
this.prevMessage = this.message;
}
}
<app-test [message]="'Hello World'"></app-test>
It is called after Angular has initialized all data-bound properties of a directive/component. It is called only once after the first ngOnChanges.
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
constructor() {}
ngOnInit() {
console.log('logged from ngOnInit');
}
}
It is called during every change detection run, and it is used to detect and act upon changes that Angular doesn't catch on its own.
import { Component, DoCheck } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements DoCheck {
ngDoCheck() {
console.log('ngDoCheck Called');
}
}
It is called after Angular has fully initialized a component's view. It is the perfect place to put any initialization logic that depends on the view.
import { AfterViewInit, Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements AfterViewInit{
ngAfterViewInit(){
console.log("after view init")
}
clickMe(){
console.log("link clicked")
}
}
<a (click)="clickMe()">Click me</a>
It is called after Angular has checked the component's view and child views. It is called after ngAfterViewInit and every subsequent ngAfterContentChecked.
import { AfterViewChecked, Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements AfterViewChecked {
ngAfterViewChecked(){
console.log("after view checked")
}
clickMe(){
console.log("link clicked")
}
}
<a (click)="clickMe()">Click me</a>
It is called after Angular has fully initialized the content of a directive. It is the perfect place to put any initialization logic that depends on the content.
import { AfterContentInit, Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements AfterContentInit {
ngAfterContentInit() {
console.log('after content init');
}
clickMe() {
console.log('clicked');
}
}
<a (click)="clickMe()">Click me</a>
It is called after the default change detector has completed checking all content of a directive. It is called after ngAfterContentInit and every subsequent ngAfterContentChecked.
import { AfterContentInit, Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements AfterContentInit {
ngAfterContentChecked() {
console.log('after content init');
}
clickMe() {
console.log('clicked');
}
}
<a (click)="clickMe()">Click me</a>
It is called just before Angular destroys the directive/component. It is used to cleanup any resources or subscriptions that the directive/component has created.
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { of } from 'rxjs';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit, OnDestroy {
private subscription: Subscription;
ngOnInit() {
const someObservable = of(1, 2, 3);
this.subscription = someObservable.subscribe((data) => {
console.log(data);
});
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
Angular provides two types of forms:
- Template-driven forms
- Reactive forms
Template-driven forms are created using directives in the template. Angular automatically tracks the value and validity of the form controls.
<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm)">
<input type="text" name="name" ngModel required />
<button type="submit">Submit</button>
</form>
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
onSubmit(form: NgForm) {
console.log(form.value);
}
}
Reactive forms are created programmatically using form controls and form groups. They provide more control and flexibility compared to template-driven forms.
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
name: ['', Validators.required],
email: ['', Validators.email],
});
}
onSubmit() {
console.log(this.form.value);
}
}
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<input type="text" formControlName="name" />
<input type="email" formControlName="email" />
<button type="submit">Submit</button>
</form>
Set Value in Template Driven forms in Angular
<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm)">
<input type="text" name="name" ngModel required />
<button type="submit">Submit</button>
</form>
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
onSubmit(form: NgForm) {
form.setValue({ name: 'John' });
}
}
FormBuilder in Reactive Forms
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
name: ['', Validators.required],
email: ['', Validators.email],
});
}
onSubmit() {
console.log(this.form.value);
}
}
SetValue & PatchValue in Angular
import { Component } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
name: '',
email: '',
});
this.form.setValue({
name: 'John',
email: 'john.doe@gmail.com',
});
this.form.patchValue({
name: 'Jane',
});
}
onSubmit() {
console.log(this.form.value);
}
}
StatusChanges in Angular Forms
import { Component } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
name: '',
email: '',
});
this.form.statusChanges.subscribe((status) => {
console.log(status);
});
}
onSubmit() {
console.log(this.form.value);
}
}
ValueChanges in Angular Forms
import { Component } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
name: '',
email: '',
});
this.form.valueChanges.subscribe((value) => {
console.log(value);
});
}
onSubmit() {
console.log(this.form.value);
}
}
FormControl
import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
name = new FormControl('');
onSubmit() {
console.log(this.name.value);
}
}
FormGroup
import { Component } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
name: '',
email: '',
});
}
onSubmit() {
console.log(this.form.value);
}
}
FormArray Example
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, FormArray } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
name: '',
emails: this.fb.array([]),
});
}
get emails() {
return this.form.get('emails') as FormArray;
}
addEmail() {
this.emails.push(this.fb.control(''));
}
removeEmail(index: number) {
this.emails.removeAt(index);
}
onSubmit() {
console.log(this.form.value);
}
}
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<input type="text" formControlName="name" />
<div formArrayName="emails">
<div *ngFor="let email of emails.controls; let i = index">
<input type="email" [formControlName]="i" />
<button type="button" (click)="removeEmail(i)">Remove</button>
</div>
</div>
<button type="button" (click)="addEmail()">Add Email</button>
<button type="submit">Submit</button>
</form>
Build Dynamic or Nested Forms using FormArray
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, FormArray } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
name: '',
addresses: this.fb.array([]),
});
}
get addresses() {
return this.form.get('addresses') as FormArray;
}
addAddress() {
this.addresses.push(
this.fb.group({
street: '',
city: '',
state: '',
zip: '',
})
);
}
removeAddress(index: number) {
this.addresses.removeAt(index);
}
onSubmit() {
console.log(this.form.value);
}
}
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<input type="text" formControlName="name" />
<div formArrayName="addresses">
<div *ngFor="let address of addresses.controls; let i = index">
<div [formGroupName]="i">
<input type="text" formControlName="street" />
<input type="text" formControlName="city" />
<input type="text" formControlName="state" />
<input type="text" formControlName="zip" />
<button type="button" (click)="removeAddress(i)">Remove</button>
</div>
</div>
</div>
<button type="button" (click)="addAddress()">Add Address</button>
<button type="submit">Submit</button>
</form>
SetValue & PatchValue in FormArray
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, FormArray } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
name: '',
addresses: this.fb.array([]),
});
this.form.setValue({
name: 'John',
addresses: [
{ street: '123 Main St', city: 'Anytown', state: 'CA', zip: '12345' },
{ street: '456 Elm St', city: 'Othertown', state: 'NY', zip: '67890' },
],
});
this.form.patchValue({
name: 'Jane',
});
}
get addresses() {
return this.form.get('addresses') as FormArray;
}
addAddress() {
this.addresses.push(
this.fb.group({
street: '',
city: '',
state: '',
zip: '',
})
);
}
removeAddress(index: number) {
this.addresses.removeAt(index);
}
onSubmit() {
console.log(this.form.value);
}
}
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<input type="text" formControlName="name" />
<div formArrayName="addresses">
<div *ngFor="let address of addresses.controls; let i = index">
<div [formGroupName]="i">
<input type="text" formControlName="street" />
<input type="text" formControlName="city" />
<input type="text" formControlName="state" />
<input type="text" formControlName="zip" />
<button type="button" (click)="removeAddress(i)">Remove</button>
</div>
</div>
</div>
<button type="button" (click)="addAddress()">Add Address</button>
<button type="submit">Submit</button>
</form>
Select Options Dropdown
import { Component } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
name: '',
gender: '',
});
}
onSubmit() {
console.log(this.form.value);
}
}
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<input type="text" formControlName="name" />
<select formControlName="gender">
<option value="male">Male</option>
<option value="female">Female</option>
</select>
<button type="submit">Submit</button>
</form>
Typed Forms in Angular
import { Component } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
interface User {
name: string;
email: string;
}
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group<User>({
name: '',
email: '',
});
}
onSubmit() {
console.log(this.form.value);
}
}
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<input type="text" formControlName="name" />
<input type="email" formControlName="email" />
<button type="submit">Submit</button>
</form>
FormRecord in Angular
import { Component } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
name: '',
email: '',
});
}
onSubmit() {
console.log(this.form.value);
}
}
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<input type="text" formControlName="name" />
<input type="email" formControlName="email" />
<button type="submit">Submit</button>
</form>
Services are used to encapsulate reusable functionality that can be shared across components. They are used to fetch data from a server, perform calculations, or interact with external services.
import { Injectable } from '@angular/core';
@Injectable
export class DataService {
getData() {
return 'Data from the service';
}
}
import { Component } from '@angular/core';
import { DataService } from './data.service';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
data: string;
constructor(private dataService: DataService) {
this.data = this.dataService.getData();
}
}
The @Injectable
decorator is used to define a service class that can be injected into other components or services.
import { Injectable } from '@angular/core';
@Injectable
export class DataService {
getData() {
return 'Data from the service';
}
}
Dependency injection is a design pattern used to create objects and manage their dependencies. It allows you to inject dependencies into a class rather than creating them within the class.
import { Injectable } from '@angular/core';
@Injectable
export class DataService {
getData() {
return 'Data from the service';
}
}
import { Component } from '@angular/core';
import { DataService } from './data.service';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
data: string;
constructor(private dataService: DataService) {
this.data = this.dataService.getData();
}
}
Providers are used to define dependencies that are injected into components, directives, pipes, and services. They are defined in the @NgModule
decorator of the root module or feature modules.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { DataService } from './data.service';
@NgModule({
imports: [BrowserModule, FormsModule],
declarations: [AppComponent],
bootstrap: [AppComponent],
providers: [DataService],
})
export class AppModule {}
Routing is used to navigate between different components in an Angular application. It allows users to move between different parts of the application by changing the URL in the browser.
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home.component';
const routes: Routes = [];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
import { Component } from '@angular/core';
@Component({
selector: 'app-home',
template: '<h1>Home Component</h1>',
})
export class HomeComponent {}
<router-outlet></router-outlet>
The router-outlet
directive is used to render the component associated with the current route.
<router-outlet></router-outlet>
The routerLink
directive is used to navigate to a different route when the element is clicked.
<a [routerLink]="['/home']">Home</a>
The routerLinkActive
directive is used to add a CSS class to an element when the associated route is active.
<a routerLink="/home" routerLinkActive="active">Home</a>
The routerLinkActiveOptions
directive is used to configure the behavior of the routerLinkActive
directive.
<a routerLink="/home" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }">Home</a>
The RouterState
class is used to access the current state of the router.
import { Router } from '@angular/router';
constructor(private router: Router) {
const state = this.router.routerState;
console.log(state);
}
The RouterEvents
class is used to listen for router events such as navigation start, navigation end, and navigation error.
import { Router, NavigationStart, NavigationEnd, NavigationError } from '@angular/router';
constructor(private router: Router) {
router.events.subscribe((event) => {
if (event instanceof NavigationStart) {
console.log('Navigation started');
}
if (event instanceof NavigationEnd) {
console.log('Navigation ended');
}
if (event instanceof NavigationError) {
console.log('Navigation error');
}
});
}
Router guards are used to control navigation and access to routes in an Angular application. They can be used to prevent unauthorized access to certain routes, redirect users to a login page, or perform other actions before navigating to a route.
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private router: Router) {}
canActivate() {
if (localStorage.getItem('token')) {
return true;
} else {
this.router.navigate(['/login']);
return false;
}
}
}
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AuthGuard } from './auth.guard';
const routes: Routes = [];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
providers: [AuthGuard],
})
export class AppRoutingModule {}
The HttpClient
service is used to make HTTP requests to a server. It provides methods for making GET, POST, PUT, DELETE, and other types of requests.
import { HttpClient } from '@angular/common/http';
constructor(private http: HttpClient) {}
getData() {
return this.http.get('https://api.example.com/data');
}
The DestroyRef provider is a utility that allows Angular components to register cleanup callbacks that are executed when the component is destroyed. This is useful for cleaning up resources, such as subscriptions, timers, or other resources that need to be released when the component is no longer in use.
import { Component, OnInit, OnDestroy } from '@angular/core';
import { DestroyRef } from '@angular/core/testing';
@Component({
selector: 'my-component',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.css']
})
export class MyComponent implements OnInit, OnDestroy {
constructor(private destroyRef: DestroyRef) {}
ngOnInit() {
}
ngOnDestroy() {
// Register a destroy callback with the DestroyRef provider.
this.destroyRef.register(() => {
// Do any cleanup tasks here.
});
}
}
Import HttpClient Module in Root Module -
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
@NgModule({
declarations: [
AppComponent
],
imports: [
HttpClientModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Import Required Module in Component/Service -
import { HttpClient } from '@angular/common/http';
Inject HttpClient service -
constructor(public http: HttpClient) {
}
getData(){
return this.http.get('url');
}
sendData(data: any){
return this.http.post('url', data);
}
updateData(data: any){
return this.http.put('url', data);
}
updateData(data: any){
return this.http.patch('url', data);
}
deleteData(id: string){
return this.http.delete(`url/${id}`);
}
Http Interceptors are a powerful feature provided by the @angular/common/http
module. They allow you to intercept and modify HTTP requests and responses in your Angular application. With interceptors, you can perform various tasks such as authentication, logging, error handling, and more. Interceptors provide a way to add global behavior to your HTTP requests and responses, making it easier to implement common functionalities across your application.
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable()
export class MyInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Modify the request before it is sent
const modifiedRequest = request.clone({
setHeaders: {
'Authorization': 'Bearer my-token'
}
});
// Pass the modified request to the next handler
return next.handle(modifiedRequest);
}
}
import { Observable } from 'rxjs';
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class MyService {
constructor(private http: HttpClient) {}
getData(): Observable<any> {
return this.http.get<any>('utl');
}
sendData(data: any): Observable<any> {
return this.http.post<any>('utl', data);
}
updateData(data: any): Observable<any> {
return this.http.put<any>('utl', data);
}
updateData(data: any): Observable<any> {
return this.http.patch<any>('utl', data);
}
deleteData(id: string): Observable<any> {
return this.http.delete<any>(`utl/${id}`);
}
}
Options—Headers/Params
import { HttpHeaders, HttpParams } from '@angular/common/http';
const headers = new HttpHeaders({
'Content-Type': 'application
'Authorization': 'Bearer my-token'
});
const params = new HttpParams()
.set('param1', 'value1')
.set('param2', 'value2');
this.http.get('url', { headers, params });
this.http.post('url', data, { headers, params });
this.http.put('url', data, { headers, params });
this.http.patch('url', data, { headers, params });
this.http.delete(`url/${id}`, { headers, params });
Options—Observe/Response Type
import { HttpResponse } from '@angular/common/http';
this.http.get('url', { observe: 'response' });
A module is a container for a group of related components, directives, pipes, and services. It is used to organize an Angular application into cohesive blocks of functionality.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
@NgModule({
imports: [BrowserModule, FormsModule],
declarations: [AppComponent],
bootstrap: [AppComponent],
})
export class AppModule {}
Lazy loading is a technique used to load modules only when they are needed. This can help reduce the initial load time of the application by loading only the necessary modules.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
@NgModule({
imports: [BrowserModule, FormsModule, AppRoutingModule],
declarations: [AppComponent],
bootstrap: [AppComponent],
})
export class AppModule {}
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [
{
path: 'page-1',
loadChildren: () =>
import('./page-1/page-1.module').then((m) => m.Page1Module),
},
{
path: 'page-2',
loadChildren: () =>
import('./page-2/page-2.module').then((m) => m.Page2Module),
},
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { Page1Component } from './page-1.component';
const routes: Routes = [
{
path: '',
component: Page1Component,
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class Page1RoutingModule {}
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Page1Component } from './page-1.component';
import { Page1RoutingModule } from './page-1-routing.module';
@NgModule({
imports: [CommonModule, Page1RoutingModule],
declarations: [Page1Component],
})
export class Page1Module {}
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { Page2Component } from './page-2.component';
const routes: Routes = [
{
path: '',
component: Page2Component,
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class Page2RoutingModule {}
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Page2Component } from './page-2.component';
import { Page2RoutingModule } from './page-2-routing.module';
@NgModule({
imports: [CommonModule, Page2RoutingModule],
declarations: [Page2Component],
})
export class Page2Module {}
<h1>Lazy Loading Example</h1>
<a routerLink="page-1">Page-1</a>
<a routerLink="page-2">Page-2</a>
<router-outlet></router-outlet>
Certainly! Let's complete the Angular Router guide with examples for the provided sections:
The Angular Router is a powerful tool that allows you to define navigation paths and routes in your application. It enables you to navigate between different components and views based on the URL path.
// app.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
const routes: Routes = [
// Define your routes here
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
To define a route with a required parameter, you can use a colon (:
) followed by the parameter name. For example, in app.module.ts
:
// app.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { UserDetailsComponent } from './user-details/user-details.component';
const routes: Routes = [
{ path: 'user/:id', component: UserDetailsComponent },
// Other routes...
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
To navigate to a route with a required parameter, you can use the Router
service. For example, in a component:
// some-component.component.ts
import { Router } from '@angular/router';
export class SomeComponent {
constructor(private router: Router) {}
navigateToUserDetails(userId: number): void {
this.router.navigate(['/user', userId]);
}
}
To define a route with an optional parameter, you can use a question mark (?
) after the parameter name. For example, in app.module.ts
:
// app.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { UserDetailsComponent } from './user-details/user-details.component';
const routes: Routes = [
{ path: 'user/:id?', component: UserDetailsComponent },
// Other routes...
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
To access route parameters in a component, you can use the ActivatedRoute
service. For example, in a component:
// user-details.component.ts
import { ActivatedRoute } from '@angular/router';
export class UserDetailsComponent {
constructor(private route: ActivatedRoute) {
// Accessing route parameters
this.route.params.subscribe(params => {
const userId = params['id'];
// Do something with the userId...
});
}
}
A routing module is a feature module that contains the routes and components related to a specific feature or section of an Angular application. It helps organize the application into smaller, more manageable modules.
// app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';
const routes: Routes = [
{
path: 'home',
component: HomeComponent
},
{
path: 'about',
component: AboutComponent
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';
@NgModule({
declarations: [
AppComponent,
HomeComponent,
AboutComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
<!-- app.component.html -->
<nav>
<a routerLink="/home">Home</a>
<a routerLink="/about">About</a>
</nav>
<router-outlet></router-outlet>
<!-- home.component.html -->
<h1>Home Component</h1>
<!-- about.component.html -->
<h1>About Component</h1>
Route parameters are used to pass data to a route in Angular. They allow you to create dynamic routes that can be customized based on user input or other factors. Route parameters are defined in the route configuration and can be accessed in the component associated with the route.
There are three types of route parameters in Angular:
Path Parameters:
Path parameters are used to extract data from the URL path. They are denoted by placing a colon (":") before the parameter name in the route configuration. Path parameters are part of the route path and can be accessed in the component associated with the route. For example:
{ path: 'users/:id', component: UserComponent }
In this example, the ":id" parameter is a path parameter. The UserComponent can retrieve the value of the ":id" parameter from the URL and use it to fetch user data.
Query Parameters:
Query parameters are used to pass data as key-value pairs in the URL query string. They are denoted by placing a question mark ("?") after the route path, followed by the parameter name and value. Query parameters are not part of the route path but can be accessed in the component associated with the route. For example:
{ path: 'search', component: SearchComponent }
In this example, the SearchComponent can access query parameters like "/search?query=angular" or "/search?query=react" and use them to perform a search operation.
Optional Parameters:
Optional parameters are used to define route parameters that are not required. They are denoted by placing a question mark ("?") after the parameter name in the route configuration. Optional parameters can be present or absent in the URL, and the component associated with the route can handle both cases. For example:
{ path: 'products/:id/:category?', component: ProductComponent }
In this example, the ":category" parameter is optional. The ProductComponent can handle URLs like "/products/123" or "/products/123/electronics" based on the presence of the ":category" parameter.
Route guards are used to control access to routes in an Angular application. They allow you to implement logic that determines whether a user is allowed to navigate to a particular route or not. Route guards can be used to protect routes based on user authentication, authorization, or other criteria.
There are four types of route guards in Angular:
CanActivate:
The CanActivate guard is used to determine whether a route can be activated or not. It is typically used to check if a user is authenticated before allowing access to a route. The guard returns a boolean value or an Observable or Promise that resolves to a boolean value. If the guard returns true, the route is activated; if it returns false, the route is blocked.
import { Injectable } from '@angular/core';
import {
CanActivate,
ActivatedRouteSnapshot,
RouterStateSnapshot,
} from '@angular/router';
import { Observable } from 'rxjs';
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean> | Promise<boolean> | boolean {
// Check if the user is authenticated
return true; // Allow access
}
}
CanActivateChild:
The CanActivateChild guard is similar to CanActivate but is used to protect child routes of a parent route. It is applied to the parent route configuration and is triggered when any child route is activated. The guard returns a boolean value or an Observable or Promise that resolves to a boolean value.
import { Injectable } from '@angular/core';
import {
CanActivateChild,
ActivatedRouteSnapshot,
RouterStateSnapshot,
} from '@angular/router';
import { Observable } from 'rxjs';
@Injectable()
export class AuthGuard implements CanActivateChild {
canActivateChild(
childRoute: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean> | Promise<boolean> | boolean {
// Check if the user is authenticated
return true; // Allow access
}
}
CanDeactivate:
The CanDeactivate guard is used to determine whether a route can be deactivated or not. It is typically used to prompt the user for confirmation before leaving a route with unsaved changes. The guard returns a boolean value or an Observable or Promise that resolves to a boolean value. If the guard returns true, the route is deactivated; if it returns false, the route is not deactivated.
import { Injectable } from '@angular/core';
import {
CanDeactivate,
ActivatedRouteSnapshot,
RouterStateSnapshot,
} from '@angular/router';
import { Observable } from 'rxjs';
@Injectable()
export class ConfirmDeactivateGuard implements CanDeactivate<any> {
canDeactivate(
component: any,
currentRoute: ActivatedRouteSnapshot,
currentState: RouterStateSnapshot,
nextState?: RouterStateSnapshot
): Observable<boolean> | Promise<boolean> | boolean {
// Check if the user wants to leave the route
return confirm('Are you sure you want to leave?');
}
}
CanLoad:
The CanLoad guard is used to determine whether a lazy-loaded module can be loaded or not. It is applied to the route configuration of a lazy-loaded module and is triggered when the module is about to be loaded. The guard returns a boolean value or an Observable or Promise that resolves to a boolean value. If the guard returns true, the module is loaded; if it returns false, the module is not loaded.
import { Injectable } from '@angular/core';
import { CanLoad, Route } from '@angular/router';
import { Observable } from 'rxjs';
@Injectable()
export class AuthGuard implements CanLoad {
canLoad(route: Route): Observable<boolean> | Promise<boolean> | boolean {
// Check if the user is authenticated
return true; // Allow loading
}
}
An observable is a class that can be used to handle asynchronous data streams. Observables are used to handle data that can arrive over time, such as data received from a server, user input, or timed events.
There are several ways to create observables in Angular:
Using the Observable Constructor: You can create an observable using the Observable
constructor and the new
keyword. The constructor takes a function as an argument, which is called when the observable is subscribed to.
import { Observable } from 'rxjs';
const observable = new Observable((observer) => {
observer.next('Hello');
observer.next('World');
observer.complete();
});
Using the of
Operator: You can create an observable from a list of values using the of
operator. The of
operator emits each value in the list in sequence.
import { of } from 'rxjs';
const observable = of('Hello', 'World');
Using the from
Operator: You can create an observable from an array, promise, or iterable using the from
operator. The from
operator emits each item in the array, promise, or iterable in sequence.
import { from } from 'rxjs';
const observable = from(['Hello', 'World']);
To receive data from an observable, you need to subscribe to it. The subscribe
method is used to subscribe to an observable and receive data emitted by the observable.
observable.subscribe({
next: (value) => console.log(value),
error: (error) => console.error(error),
complete: () => console.log('Complete')
});
-
Observables:
- Observables are lazy, meaning they only execute when subscribed to.
- Observables can emit multiple values over time.
- Observables can be canceled using the
unsubscribe
method. - Observables can be transformed and combined using operators.
- Observables are used for handling streams of data, such as user input, server responses, and events.
-
Promises:
- Promises are eager, meaning they execute immediately when created.
- Promises can only emit a single value.
- Promises cannot be canceled once created.
- Promises do not have built-in transformation or combination methods.
- Promises are used for handling asynchronous operations that produce a single result, such as HTTP requests and file reads.
In Angular, managing subscriptions is crucial to avoid memory leaks and improve the performance of your application. Here are five ways to unsubscribe in Angular:
-
Using the takeUntil operator:
- Create a subject to act as a notifier.
- In your component, create a private property for the subject.
- Subscribe to observables using the takeUntil operator with the subject as the parameter.
- Emit a value on the subject when you want to unsubscribe, typically in the ngOnDestroy lifecycle hook.
- In the ngOnDestroy hook, call complete() on the subject to stop emitting values.
import { Component, OnDestroy } from '@angular/core'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-example', templateUrl: './example.component.html', styleUrls: ['./example.component.css'] }) export class ExampleComponent implements OnDestroy { private unsubscribe$ = new Subject<void>(); ngOnInit() { // Subscribe to an observable someObservable.pipe(takeUntil(this.unsubscribe$)).subscribe((data) => { // Handle data }); } ngOnDestroy() { this.unsubscribe$.next(); this.unsubscribe$.complete(); } }
-
Using the async pipe:
- In your template, use the async pipe to subscribe to observables directly.
- Angular automatically handles the subscription and unsubscription for you.
- Ensure you don't manually subscribe to the observable in your component.
<div>{{ someObservable$ | async }}</div>
-
Using the Subscription object:
- Declare a Subscription property in your component.
- Assign the subscription to the property when subscribing.
- In the ngOnDestroy hook, unsubscribe from the subscription.
import { Component, OnDestroy } from '@angular/core'; import { Subscription } from 'rxjs'; @Component({ selector: 'app-example', templateUrl: './example.component.html', styleUrls: ['./example.component.css'] }) export class ExampleComponent implements OnDestroy { private subscription: Subscription; ngOnInit() { // Assign the subscription this.subscription = someObservable.subscribe((data) => { // Handle data }); } ngOnDestroy() { // Unsubscribe from the subscription this.subscription.unsubscribe(); } }
-
Using the unsubscribe operator:
- Store the subscription in a variable.
- Call the unsubscribe method on the subscription in the ngOnDestroy hook.
import { Component, OnDestroy } from '@angular/core'; @Component({ selector: 'app-example', templateUrl: './example.component.html', styleUrls: ['./example.component.css'] }) export class ExampleComponent implements OnDestroy { private subscription; ngOnInit() { // Assign the subscription this.subscription = someObservable.subscribe((data) => { // Handle data }); } ngOnDestroy() { // Unsubscribe from the subscription this.subscription.unsubscribe(); } }
-
Using the ngOnDestroy hook and manual unsubscription:
- Declare an array to store all the subscriptions.
- Push the subscription to the array when subscribing.
- Loop through the array in the ngOnDestroy hook and unsubscribe from each subscription.
import { Component, OnDestroy } from '@angular/core'; import { Subscription } from 'rxjs'; @Component({ selector: 'app-example', templateUrl: './example.component.html', styleUrls: ['./example.component.css'] }) export class ExampleComponent implements OnDestroy { private subscriptions: Subscription[] = []; ngOnInit() { // Push the subscription to the array this.subscriptions.push(someObservable.subscribe((data) => { // Handle data })); } ngOnDestroy() { // Unsubscribe from all subscriptions this.subscriptions.forEach(subscription => subscription.unsubscribe()); } }
Renderer2 is a utility class that provides methods to manipulate and interact with the DOM (Document Object Model). It is used to perform operations such as creating, modifying, and removing elements, applying styles, and listening to events.
import { Component, Renderer2, ElementRef } from '@angular/core';
@Component({
selector: 'app-example',
template: `
<button (click)="changeColor()">Change Color</button>
`
})
export class ExampleComponent {
constructor(private renderer: Renderer2, private el: ElementRef) { }
changeColor() {
const button = this.el.nativeElement.querySelector('button');
this.renderer.setStyle(button, 'background-color', 'red');
}
}
Just-in-Time (JIT) is a type of compilation that compiles your app in the browser at runtime. This is the default compilation mode for Angular applications.
- Faster development cycle as changes can be seen immediately.
- No build step required during development.
- More flexible for dynamic template generation.
Ahead-of-Time (AOT) is a type of compilation that compiles your app at build time. This mode is used to pre-compile your Angular application before deployment.
- Faster startup times as the browser only needs to execute the compiled code.
- Improved performance due to optimized and pre-compiled templates.
- Better security as the templates are already compiled and validated before deployment.
- Smaller bundle sizes since the templates are not included.
Feature | AOT | JIT |
---|---|---|
Compilation time | Build time | Runtime |
Application size | Smaller | Larger |
Application load time | Faster | Slower |
Debugging | More difficult | Easier |
Development | More difficult | Easier |
Performance | Better | Worse |
Deferrable views can be used in component template to defer the loading of select dependencies within that template.
@defer {
<large-component />
}
import { BrowserModule, Title } from '@angular/platform-browser';
import { BrowserModule, Title } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [Title],
bootstrap: [AppComponent]
})
export class AppModule { }
export class TitleComponent implements OnInit {
constructor(private title:Title) { }
}
ngOnInit() {
this.title.setTitle("Learn Angular")
}
import { Component, OnInit } from '@angular/core';
import { Title, MetaDefinition } from '@angular/platform-browser';
@Component({
template: `<h1>App Component</h1>`
})
export class AppComponent implements OnInit {
title = 'App Component';
constructor(private title:Title){
}
ngOnInit() {
this.title.setTitle("Learn Angular")
}
}
// app.module.ts
import { BrowserModule, Title } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HomeComponent } from './home.component';
@NgModule({
declarations: [
AppComponent, HomeComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [Title],
bootstrap: [AppComponent]
})
export class AppModule { }
// app-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './home.component';
const routes: Routes = [
{path: 'home', component:HomeComponent},
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
// app.component.ts
import { Component } from '@angular/core';
import { Title } from '@angular/platform-browser';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'Title Service Example';
constructor(private titleService:Title) {
}
ngOnInit() {
this.titleService.setTitle(this.title);
}
}
<!-- app.component.html -->
<h1>Title Service Example</h1>
<ul>
<li><a [routerLink]="['/home']">Home</a> </li>
</ul>
<router-outlet></router-outlet>
// home.component.ts
import { Component, OnInit } from '@angular/core';
import { Title } from '@angular/platform-browser';
@Component({
template: `<h1>Home Component</h1>`
})
export class HomeComponent implements OnInit {
title = 'Home Component Title';
constructor(private titleService:Title){
}
ngOnInit() {
this.titleService.setTitle(this.title);
}
}
// app.module.ts
import { BrowserModule, Title } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HomeComponent } from './home.component';
@NgModule({
declarations: [
AppComponent, HomeComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [Title],
bootstrap: [AppComponent]
})
export class AppModule { }
// app-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './home.component';
import { PParentComponent } from './parent.component';
import { ChildComponent } from './child.component';
const routes: Routes = [
{path: '', component:HomeComponent, data : {title:'Title for Home Component'}},
{path: 'parent', component:ParentComponent, data : {title:'Title for Parent Component'},
children: [
{ path: 'child', component:ChildComponent, data : {title:'Title for Child Component'}}
]
},
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
// app.component.ts
import { Component } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
import { filter, map } from 'rxjs/operators';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(
private router: Router,
private activatedRoute: ActivatedRoute,
private titleService: Title
) { }
ngOnInit() {
this.router.events.pipe(
filter(event => event instanceof NavigationEnd),
)
.subscribe(() => {
var rt = this.getChild(this.activatedRoute)
rt.data.subscribe(data => {
console.log(data);
this.titleService.setTitle(data.title)})
})
}
getChild(activatedRoute: ActivatedRoute) {
if (activatedRoute.firstChild) {
return this.getChild(activatedRoute.firstChild);
} else {
return activatedRoute;
}
}
}
<!-- app.component.html -->
<h1>Dynamic Title Example</h1>
<ul>
<li><a routerLink="">Home</a> </li>
<li><a [routerLink]="['/parent']">Parent</a> </li>
<li><a [routerLink]="['/child']">Child</a> </li>
</ul>
<router-outlet></router-outlet>
// home.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
template: `<h1>Home Component</h1>`
})
export class HomeComponent implements OnInit {
constructor(){
}
ngOnInit() {
}
}
// parent.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
template: `<h1>Parent Component</h1>
<router-outlet></router-outlet>
`
})
export class ParentComponent implements OnInit {
constructor(){
}
ngOnInit() {
}
}
// child.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
template: `<h1>Child Component</h1>`
})
export class ChildComponent implements OnInit {
constructor(){
}
ngOnInit() {
}
}
import { BrowserModule, Meta } from '@angular/platform-browser';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [Meta],
bootstrap: [AppComponent]
})
export class AppModule { }
import { Component, OnInit } from '@angular/core';
import { Meta, MetaDefinition } from '@angular/platform-browser';
@Component({
template: `<h1>App Component</h1>`
})
export class AppComponent implements OnInit {
title = 'App Component';
constructor(private metaService:Meta){
}
ngOnInit() {
this.metaService.addTag( { name:'description',content:"Article Description"});
}
}
Adding Tags with addTag() & addTags()
this.metaService.addTag( { name:'description',content:"Article Description"});
this.metaService.addTag(
{ name: 'description', content: 'Article Description' },
{ name: 'robots', content: 'index,follow' },
{ property: 'og:title', content: 'Content Title for social media' }
);
Reading the Tags with getTag()
this.metaService.getTag("name='description'")
Update the Tag with updateTag()
this.metaService.updateTag( { name:'robots', content:'index, nofoloow'},"name='robots'");
Removing the Tag with removeTag()
this.metaService.removeTag("name='robots'");
The security of an Angular application is a critical aspect that needs to be considered during development. Here are some best practices to enhance the security of your Angular application:
Cross-site scripting (XSS) is a security vulnerability that allows attackers to inject malicious scripts into web pages viewed by other users. To prevent XSS attacks in Angular applications, you can use the following best practices:
- Use Angular's built-in sanitization mechanisms to sanitize user input and prevent script injection.
- Avoid using unsafe methods like innerHTML and instead use Angular's data binding syntax to render dynamic content.
- Use Angular's built-in security features like Content Security Policy (CSP) to restrict the sources of scripts and other resources that can be loaded by your application.
- Enable strict mode in Angular templates to prevent template expressions from executing arbitrary code.
- Use Angular's HttpClient module to make HTTP requests and automatically sanitize responses to prevent XSS attacks.
Angular provides a built-in security model to prevent cross-site scripting (XSS) attacks in applications. This security model includes the following features:
- Automatic sanitization of user input: Angular automatically sanitizes user input to prevent script injection and other security vulnerabilities.
- Strict mode in templates: Angular templates run in strict mode by default, which prevents template expressions from executing arbitrary code.
- Content Security Policy (CSP): Angular applications can use CSP to restrict the sources of scripts and other resources that can be loaded by the application.
- Trusted Types: Angular supports Trusted Types, a new web platform feature that helps prevent DOM-based XSS attacks by enforcing strict type checking on DOM APIs.
Angular provides a built-in sanitization mechanism to prevent cross-site scripting (XSS) attacks in applications. Sanitization is the process of cleaning user input to remove potentially dangerous content, such as script tags and event handlers. Angular uses security contexts to determine how to sanitize user input based on its intended use.
Angular provides the following security contexts for sanitization:
- HTML: Sanitizes user input for use in HTML contexts, such as rendering dynamic content in templates.
- Style: Sanitizes user input for use in CSS contexts, such as setting inline styles.
- Script: Sanitizes user input for use in script contexts, such as event handlers and script tags.
- URL: Sanitizes user input for use in URL contexts, such as setting href attributes.
- Resource URL: Sanitizes user input for use in resource URL contexts, such as loading external resources.
import { Component } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
@Component({
selector: 'app-root',
template: `<div [innerHTML]="safeHtml"></div>`
})
export class AppComponent {
safeHtml: SafeHtml;
constructor(private sanitizer: DomSanitizer) {
const untrustedHtml = '<img src=x onerror=alert(1)>';
this.safeHtml = this.sanitizer.bypassSecurityTrustHtml(untrustedHtml);
}
}
Directly using the DOM APIs to manipulate the DOM can introduce security vulnerabilities in Angular applications. To prevent XSS attacks, avoid using unsafe methods like innerHTML and instead use Angular's built-in sanitization mechanisms to render dynamic content safely.
import { Renderer2 } from '@angular/core';
constructor(private renderer: Renderer2, private sanitizer: DomSanitizer) { }
const div = this.renderer.createElement('div');
const unsafeContent = '<script>alert("XSS")</script>';
const sanitizedContent = this.sanitizer.sanitize(SecurityContext.HTML, unsafeContent);
this.renderer.setProperty(div, 'innerHTML', sanitizedContent);
document.body.appendChild(div);
Angular provides a mechanism to trust safe values and bypass the built-in sanitization mechanisms when rendering trusted content. To trust a safe value, you can use the bypassSecurityTrustHtml, bypassSecurityTrustStyle, bypassSecurityTrustScript, bypassSecurityTrustUrl, and bypassSecurityTrustResourceUrl methods provided by the DomSanitizer service.
const safeHtml = this.sanitizer.bypassSecurityTrustHtml('<b>Safe Content</b>');
Content Security Policy (CSP) is a security feature that helps prevent cross-site scripting (XSS) attacks by restricting the sources of scripts and other resources that can be loaded by a web application. Angular applications can use CSP to define a policy that specifies which content is allowed to be loaded by the application.
To enable CSP in an Angular application, you can add a Content-Security-Policy header to the HTTP response from the server. The CSP header should include directives that restrict the sources of scripts, styles, images, fonts, and other resources that can be loaded by the application.
Content-Security-Policy: default-src 'self'; script-src 'self' https://example.com; style-src 'self' https://example.com; img-src 'self' https://example.com; font-src 'self' https://example.com;
Trusted Types is a new web platform feature that helps prevent DOM-based cross-site scripting (XSS) attacks by enforcing strict type checking on DOM APIs. Angular applications can use Trusted Types to ensure that only trusted values are passed to DOM APIs, preventing script injection and other security vulnerabilities.
To enable Trusted Types in an Angular application, you can configure the Trusted Types policy using the TrustedTypesConfig token provided by Angular. The policy can specify which types of values are considered trusted and enforce strict type checking on DOM APIs.
import { InjectionToken } from '@angular/core';
export const TRUSTED_TYPES_CONFIG = new InjectionToken('TRUSTED_TYPES_CONFIG');
const trustedTypesConfig = {
createPolicy: (name, policy) => {
return policy;
}
};
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { TRUSTED_TYPES_CONFIG } from './trusted-types.config';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule
],
providers: [
{ provide: TRUSTED_TYPES_CONFIG, useValue: trustedTypesConfig }
],
bootstrap: [AppComponent]
})
export class AppModule { }
The Angular Ahead-of-Time (AOT) template compiler compiles Angular templates at build time, which helps prevent cross-site scripting (XSS) attacks by statically analyzing the templates and generating optimized code. AOT compilation eliminates the need for the browser to compile templates at runtime, reducing the risk of template injection vulnerabilities.
To enable AOT compilation in an Angular application, you can use the ngc command to compile the application ahead of time. AOT compilation is recommended for production builds to improve performance, security, and compatibility with Content Security Policy (CSP) restrictions.
ng build --aot
Server-side XSS protection is a security feature that helps prevent cross-site scripting (XSS) attacks by validating and sanitizing user input on the server before rendering it in the browser. To protect against XSS attacks, you can implement server-side input validation and sanitization to ensure that user input is safe and does not contain malicious content.
Angular applications can be vulnerable to various HTTP-level attacks, such as cross-site request forgery (CSRF), cross-site scripting (XSS), and cross-site script inclusion (XSSI). To protect against these vulnerabilities, you can use Angular's built-in security features, such as HttpClient XSRF/CSRF protection, custom cookie/header names, and disabling XSRF protection.
Cross-site request forgery (CSRF) is a security vulnerability that allows attackers to execute unauthorized actions on behalf of authenticated users. To prevent CSRF attacks in Angular applications, you can use Angular's built-in XSRF/CSRF protection mechanism to add a token to HTTP requests and validate it on the server.
import { HttpClientModule } from '@angular/common/http';
import { HttpClientXsrfModule } from '@angular/common/http';
@NgModule({
imports: [
HttpClientModule,
HttpClientXsrfModule.withOptions({
cookieName: 'XSRF-TOKEN',
headerName: 'X-XSRF-TOKEN'
})
]
})
export class AppModule { }
Angular's HttpClient module provides built-in support for cross-site request forgery (CSRF) protection using the XSRF/CSRF token mechanism. The HttpClientXsrfModule.withOptions method allows you to configure custom cookie and header names for the XSRF/CSRF token.
import { HttpClientModule } from '@angular/common/http';
import { HttpClientXsrfModule } from '@angular/common/http';
@NgModule({
imports: [
HttpClientModule,
HttpClientXsrfModule.withOptions({
cookieName: 'XSRF-TOKEN',
headerName: 'X-XSRF-TOKEN'
})
]
})
export class AppModule { }
Angular's HttpClient module allows you to configure custom cookie and header names for the XSRF/CSRF token using the HttpClientXsrfModule.withOptions method. By specifying custom names for the XSRF/CSRF token, you can enhance the security of your application and prevent CSRF attacks.
import { HttpClientModule } from '@angular/common/http';
import { HttpClientXsrfModule } from '@angular/common/http';
@NgModule({
imports: [
HttpClientModule,
HttpClientXsrfModule.withOptions({
cookieName: 'XSRF-TOKEN',
headerName: 'X-XSRF-TOKEN'
})
]
})
export class AppModule { }
Angular's HttpClient module provides built-in support for cross-site request forgery (CSRF) protection using the XSRF/CSRF token mechanism. If you want to disable XSRF protection for specific requests, you can use the { withCredentials: true } option in the HttpClient request.
import { HttpClient } from '@angular/common/http';
constructor(private http: HttpClient) { }
this.http.get('/api/data', { withCredentials: true });
Cross-site script inclusion (XSSI) is a security vulnerability that allows attackers to include external scripts in an application and execute malicious code. To prevent XSSI attacks in Angular applications, you can use Angular's built-in security features, such as HttpClient XSSI protection, to validate and sanitize external script responses.
Auditing Angular applications is an essential step to identify and fix security vulnerabilities in the codebase. You can use various tools and techniques to audit Angular applications, such as security scanners, code reviews, penetration testing, and security best practices.
A standalone component is a type of component which is not part of any Angular module. It provides a simplified way to build Angular applications.
Angular Signals is a powerful system that provides detailed monitoring of state usage within an application, enabling the framework to efficiently optimize rendering updates.
import { Component, OnInit } from '@angular/core';
import { signal, computed } from '@angular/core'; // Import from '@angular/core'
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
count = signal(0);
doubleCount = computed(() => this.count() * 2);
constructor() {}
ngOnInit() {
// Optional logging for debugging displayedCount changes
// console.log('Displayed count changed to:', this.displayedCount());
}
incrementCount() {
this.count.set(this.count() + 1);
}
decrementCount() {
this.count.update((value) => Math.max(0, value - 1));
}
}
<h1>Angular Signals Example</h1>
<button (click)="incrementCount()" style="margin-right: 10px;">Increment Count</button>
<button (click)="decrementCount()">Decrement Count</button>
<p>Count: {{ count() }}</p>
<p>Double Count: {{ doubleCount() }}</p>
DEPLOYMENT TO | PACKAGE |
---|---|
Firebase hosting | ng add @angular/fire |
Vercel | vercel init angular |
Netlify | ng add @netlify-builder/deploy |
GitHub pages | ng add angular-cli-ghpages |
NPM | ng add ngx-deploy-npm |
Amazon Cloud S3 | ng add @jefiozie/ngx-aws-deploy |
Angular's animation system is built on CSS functionality in order to animate any property that the browser considers animatable. These properties includes positions, sizes, transforms, colors, borders etc. The Angular modules for animations are @angular/animations and @angular/platform-browser.
npm install @angular/animations
To use Angular animations in an Angular application, you need to import the BrowserAnimationsModule module in the app.module.ts file.
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
animations: [
trigger('fadeInOut', [
transition(':enter', [
style({ opacity: 0 }),
animate('1s', style({ opacity: 1 }))
]),
transition(':leave', [
animate('1s', style({ opacity: 0 }))
])
])
]
})
export class AppComponent {
show = false;
toggle() {
this.show = !this.show;
}
}
<button (click)="toggle()">Toggle</button>
<div *ngIf="show" @fadeInOut>
<h1>Angular Animation Example</h1>
</div>
Angular Universal is a server-side rendering (SSR) solution for Angular applications that allows you to render your application on the server and send the fully rendered HTML to the client. This can improve performance, SEO, and user experience by reducing the time to first contentful paint and enabling search engines to crawl and index your application.
To create an Angular Universal application, you can use the Angular CLI to generate a new project with the Universal schematic.
ng new --ssr
To add Angular Universal to an existing Angular application, you can use the Angular CLI to add the Universal schematic to the project.
ng add @angular/ssr
Bootstrap is a popular front-end framework for building responsive web applications. It provides a set of CSS and JavaScript components that can be used to create modern and mobile-friendly user interfaces.
npm install bootstrap
To use Bootstrap in an Angular application, you need to import the Bootstrap CSS file in the styles array of the angular.json file.
"styles": [
"node_modules/bootstrap/dist/css/bootstrap.min.css",
"src/styles.css"
]
Angular Material is a UI component library for Angular applications that provides a set of reusable and customizable components, such as buttons, cards, dialogs, and menus. It is built on top of the Angular CDK (Component Dev Kit) and follows the Material Design guidelines.
ng add @angular/material
To use Angular Material in an Angular application, you need to import the required modules in the app.module.ts file.
import { MatSliderModule } from '@angular/material/slider';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
MatSliderModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Tailwind CSS is a utility-first CSS framework that provides a set of pre-built utility classes for styling web applications. It allows you to build custom designs by composing utility classes together, rather than writing custom CSS styles.
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init
// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{html,ts}",
],
theme: {
extend: {},
},
plugins: [],
};
/* styles.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
PrimeNG is a popular UI component library for Angular applications that provides a set of rich and customizable components, such as data tables, calendars, dialogs, and charts. It is built on top of the PrimeFaces library and follows the PrimeNG design guidelines.
npm install primeng
To use PrimeNG in an Angular application, you need to import the required styles and modules in the angular.json file.
// angular.json
"styles": [
"node_modules/primeng/resources/themes/saga-blue/theme.css",
"node_modules/primeng/resources/primeng.min.css",
"src/styles.css"
]
/* styles.css */
@import 'primeng/resources/themes/saga-blue/theme.css';
@import 'primeng/resources/primeng.min.css';
Progressive Web Apps (PWAs) are web applications that provide a native app-like experience to users, including offline support, push notifications, and home screen installation. Angular provides built-in support for creating PWAs using the @angular/pwa package.
ng add @angular/pwa
To configure the PWA settings, you can modify the ngsw-config.json file in the src/ directory.
{
"index": "/index.html",
"assetGroups": [
{
"name": "app",
"installMode": "prefetch",
"resources": {
"files": [
"/favicon.ico",
"/index.html",
"/*.css",
"/*.js"
]
}
}
]
}
To build the PWA, you can run the ng build --prod command with the --configuration=production flag.
ng build --prod --configuration=production
The service worker is a script that runs in the background of the browser and handles tasks such as caching assets, intercepting network requests, and providing offline support. Angular's service worker is generated automatically when you create a PWA using the @angular/pwa package.
Offline Support - The service worker caches assets and intercepts network requests to provide offline support for the application.
Push Notifications - The service worker can receive push notifications from the server and display them to the user.
Background Sync - The service worker can perform background sync tasks, such as sending data to the server when the network connection is available.
Home Screen Installation - The service worker can prompt the user to install the application on the home screen for quick access.
Installing Angular CLI
npm install -g @angular/cli
Help
ng help
Check version
ng version
Create, build, and serve a new, basic Angular project cli command
ng new my-first-project
cd my-first-project
ng serve
Generating new application
ng new app-name
Create new app without installing cli
npm init @angular app-name
Component
ng g c component-name
ng generate component component-name
Adding External libraries
ng add
Build
ng build
Running project
ng serve
Run project on particular port
ng serve --port=portname
// example
ng serve --port=3000
Run project and open the url in default browser
ng serve --open
Update
ng update
Directive
ng generate directive component-name
ng g directive component-name
Module
ng generate module module-name
ng g m module-name
Service
ng generate service component-name
ng g service component-name
Routing Module
ng g module module-name --routing
ng g m module-name --routing
Component with module, routing module
ng generate module component-name --route component-name --module app.module
Pipe
ng g pipe pipe-name
Enum
ng g enum some-enum
Class
ng g cl my-class
Interface
ng g interface my-interface
Guard
ng g guard guard-name
Multiple Projects in one Angular App
ng generate application sub-app-name
ng new app-name --create-application=false
Generate environments
ng generate environments
Angular | Node.js | TypeScript | RxJS |
---|---|---|---|
18.0.x | ^18.19.1 || ^20.11.1 || ^22.0.0 | >=5.4.0 <5.5.0 | ^6.5.3 || ^7.4.0 |
17.3.x | ^18.13.0 || ^20.9.0 | >=5.2.0 <5.5.0 | ^6.5.3 || ^7.4.0 |
17.1.x || 17.2.x | ^18.13.0 || ^20.9.0 | >=5.2.0 <5.4.0 | ^6.5.3 || ^7.4.0 |
17.0.x | ^18.13.0 || ^20.9.0 | >=5.2.0 <5.3.0 | ^6.5.3 || ^7.4.0 |
16.1.x || 16.2.x | ^16.14.0 || ^18.10.0 | >=4.9.3 <5.2.0 | ^6.5.3 || ^7.4.0 |
16.0.x | ^16.14.0 || ^18.10.0 | >=4.9.3 <5.1.0 | ^6.5.3 || ^7.4.0 |
Angular Core
import { Component } from '@angular/core'; // Component decorator
import { NgModule } from '@angular/core'; // NgModule decorator
import { RouterModule, Routes } from '@angular/router'; // Routing module
import { FormsModule } from '@angular/forms'; // Forms module
import { ReactiveFormsModule } from '@angular/forms'; // Reactive forms module
import { HttpClientModule } from '@angular/common/http'; // HTTP client module
import { BrowserModule } from '@angular/platform-browser'; // Browser module
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; // Animations module
import { CommonModule } from '@angular/common'; // Common module
import { NgModel } from '@angular/forms'; // NgModel directive
import { NgForm } from '@angular/forms'; // NgForm directive
import { FormGroup, FormControl, Validators } from '@angular/forms'; // Form group, form control, validators
import { HttpClient } from '@angular/common/http'; // HTTP client
import { ActivatedRoute } from '@angular/router'; // Route parameters
import { Router } from '@angular/router'; // Router service
import { Title } from '@angular/platform-browser'; // Title service
import { Meta } from '@angular/platform-browser'; // Meta service
import { Renderer2 } from '@angular/core'; // Renderer2 service
import { ElementRef } from '@angular/core'; // ElementRef service
import { ViewChild } from '@angular/core'; // ViewChild decorator
import { ViewContainerRef } from '@angular/core'; // ViewContainerRef service
import { ComponentFactoryResolver } from '@angular/core'; // ComponentFactoryResolver service
import { ChangeDetectorRef } from '@angular/core'; // ChangeDetectorRef service
import { Pipe, PipeTransform } from '@angular/core'; // Pipe decorator, PipeTransform interface
import { Injectable } from '@angular/core'; // Injectable decorator
import { EventEmitter } from '@angular/core'; // EventEmitter class
import { Output } from '@angular/core'; // Output decorator
import { Input } from '@angular/core'; // Input decorator
import { HostListener } from '@angular/core'; // HostListener decorator
import { HostBinding } from '@angular/core'; // HostBinding decorator
import { ContentChild } from '@angular/core'; // ContentChild decorator
import { ContentChildren } from '@angular/core'; // ContentChildren decorator
import { QueryList } from '@angular/core'; // QueryList class
import { AfterContentInit } from '@angular/core'; // AfterContentInit interface
import { AfterContentChecked } from '@angular/core'; // AfterContentChecked interface
import { AfterViewInit } from '@angular/core'; // AfterViewInit interface
import { AfterViewChecked } from '@angular/core'; // AfterViewChecked interface
import { OnInit } from '@angular/core'; // OnInit interface
import { OnDestroy } from '@angular/core'; // OnDestroy interface
import { OnChanges } from '@angular/core'; // OnChanges interface
import { SimpleChanges } from '@angular/core'; // SimpleChanges class
import { DoCheck } from '@angular/core'; // DoCheck interface
import { KeyValueDiffers } from '@angular/core'; // KeyValueDiffers service
import { KeyValueDiffer } from '@angular/core'; // KeyValueDiffer interface
import { KeyValueChanges } from '@angular/core'; // KeyValueChanges interface
import { KeyValueChangeRecord } from '@angular/core'; // KeyValueChangeRecord interface
import { IterableDiffers } from '@angular/core'; // IterableDiffers service
import { IterableDiffer } from '@angular/core'; // IterableDiffer interface
import { IterableChanges } from '@angular/core'; // IterableChanges interface
import { IterableChangeRecord } from '@angular/core'; // IterableChangeRecord interface
import { ChangeDetectionStrategy } from '@angular/core'; // ChangeDetectionStrategy enum
import { ChangeDetectorRef } from '@angular/core'; // ChangeDetectorRef service
import { NgZone } from '@angular/core'; // NgZone service
import { ApplicationRef } from '@angular/core'; // ApplicationRef service
import { ComponentRef } from '@angular/core'; // ComponentRef class
import { ComponentFactory } from '@angular/core'; // ComponentFactory class
import { ComponentFactoryResolver } from '@angular/core'; // ComponentFactoryResolver service
import { ViewContainerRef } from '@angular/core'; // ViewContainerRef service
import { TemplateRef } from '@angular/core'; // TemplateRef class
import { EmbeddedViewRef } from '@angular/core'; // EmbeddedViewRef class
Angular Material
import { MatDialog } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTableDataSource } from '@angular/material/table';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatButtonModule } from '@angular/material/button';
import { MatInputModule } from '@angular/material/input';
import { MatIconModule } from '@angular/material/icon';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatMenuModule } from '@angular/material/menu';
import { MatSelectModule } from '@angular/material/select';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatNativeDateModule } from '@angular/material/core';
import { MatCardModule } from '@angular/material/card';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatDialogModule } from '@angular/material/dialog';
import { MatTooltipModule } from '@angular/material/tooltip';
import { MatRadioModule } from '@angular/material/radio';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { MatTabsModule } from '@angular/material/tabs';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatExpansionModule } from '@angular/material/expansion';
import { MatGridListModule } from '@angular/material/grid-list';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatChipsModule } from '@angular/material/chips';
import { MatListModule } from '@angular/material/list';
import { MatStepperModule } from '@angular/material/stepper';
import { MatBadgeModule } from '@angular/material/badge';
import { MatBottomSheetModule } from '@angular/material/bottom-sheet';
import { MatButtonToggleModule } from '@angular/material/button-toggle';
import { MatDividerModule } from '@angular/material/divider';
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatRippleModule } from '@angular/material/core';
import { MatSliderModule } from '@angular/material/slider';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { MatSortModule } from '@angular/material/sort';
import { MatTreeModule } from '@angular/material/tree';
RxJS
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { ReplaySubject } from 'rxjs/ReplaySubject';
import { AsyncSubject } from 'rxjs/AsyncSubject';
import { Subscription } from 'rxjs/Subscription';
import { from } from 'rxjs';
import { fromEvent } from 'rxjs';
import { interval } from 'rxjs';
import { timer } from 'rxjs';
import { merge } from 'rxjs';
import { zip } from 'rxjs';
import { combineLatest } from 'rxjs';
import { concat } from 'rxjs';
import { forkJoin } from 'rxjs';
import { race } from 'rxjs';
import { map } from 'rxjs/operators';
import { filter } from 'rxjs/operators';
import { reduce } from 'rxjs/operators';
import { tap } from 'rxjs/operators';
import { catchError } from 'rxjs/operators';
import { retry } from 'rxjs/operators';
import { switchMap } from 'rxjs/operators';
import { take } from 'rxjs/operators';
import { debounceTime } from 'rxjs/operators';
import { distinctUntilChanged } from 'rxjs/operators';
import { scan } from 'rxjs/operators';
import { mergeMap } from 'rxjs/operators';
import { exhaustMap } from 'rxjs/operators';
import { concatMap } from 'rxjs/operators';
import { takeUntil } from 'rxjs/operators';
import { finalize } from 'rxjs/operators';
import { share } from 'rxjs/operators';
import { shareReplay } from 'rxjs/operators';
import { buffer } from 'rxjs/operators';
import { bufferCount } from 'rxjs/operators';
import { bufferTime } from 'rxjs/operators';
import { bufferToggle } from 'rxjs/operators';
import { bufferWhen } from 'rxjs/operators';
import { combineAll } from 'rxjs/operators';
import { concatAll } from 'rxjs/operators';
import { count } from 'rxjs/operators';
import { endWith } from 'rxjs/operators';
import { every } from 'rxjs/operators';
import { exhaust } from 'rxjs/operators';
import { first } from 'rxjs/operators';
import { groupBy } from 'rxjs/operators';
import { ignoreElements } from 'rxjs/operators';
import { isEmpty } from 'rxjs/operators';
import { last } from 'rxjs/operators';
import { max } from 'rxjs/operators';
import { mergeAll } from 'rxjs/operators';
import { min } from 'rxjs/operators';
import { pairwise } from 'rxjs/operators';
import { partition } from 'rxjs/operators';
import { pluck } from 'rxjs/operators';
Firebase
import { AngularFireModule } from "@angular/fire/compat";
import { AngularFireAuthModule } from "@angular/fire/compat/auth";
import { AngularFireStorageModule } from '@angular/fire/compat/storage';
import { AngularFirestoreModule } from '@angular/fire/compat/firestore';
import { AngularFireDatabaseModule } from '@angular/fire/compat/database';
import { AngularFireStorage } from '@angular/fire/storage';
import { AngularFireModule } from '@angular/fire';
import { AngularFireAuthModule } from '@angular/fire/auth';
import { AngularFireDatabaseModule } from '@angular/fire/database';
import { AngularFireStorageModule } from '@angular/fire/storage';
import { AngularFirestoreModule } from '@angular/fire/firestore';
import { AngularFireFunctionsModule } from '@angular/fire/functions';
import { AngularFireMessagingModule } from '@angular/fire/messaging';
import { AngularFirePerformanceModule } from '@angular/fire/performance';
import { AngularFireRemoteConfigModule } from '@angular/fire/remote-config';
import { AngularFireAnalyticsModule } from '@angular/fire/analytics';
import { AngularFireAuthGuardModule } from '@angular/fire/auth-guard';
MVVM stands for Model-View-ViewModel. It is a design pattern that separates the user interface (View) from the business logic (Model) using a ViewModel. The ViewModel acts as an intermediary between the View and the Model, providing data binding and event handling.
MVC stands for Model-View-Controller. It is a design pattern that separates the user interface (View) from the business logic (Model) using a Controller. The Controller acts as an intermediary between the View and the Model, handling user input and updating the Model.
TypeScript is JavaScript with syntax for types. TypeScript is a superset of JavaScript that compiles to plain JavaScript. It is developed and maintained by Microsoft.
Reactive Extensions Library for JavaScript - RxJS is a library for reactive programming using Observables, to make it easier to compose asynchronous or callback-based code.
NgRx is a Reactive libraries for Angular. It provides state management, side effects, and route handling. It is inspired by Redux. It is a set of Angular libraries to help manage state at scale in Angular applications.
NgXS is a state management pattern + library for Angular. It acts as a single source of truth for your application's state, providing simple rules for predictable state mutations.
- Awesomw Angular
- Angular JumpStart
- Angular Interview Questions by Sudheerj
- Angular Learning Resources
- CodAffection
- Bezkoder
- Angular Interview Questions by Yonet
- Angular Basics ( v14.x )
- Official Documentation
- Tektutorialshub
- W3School
- GeeksForGeeks
- DevDocs
- Freecodecamp
- Javatpoint
- Tutorialspoint
- Udemy
- YouTube
- Stackoverflow
- NX Blog
- Indepthdev
- Angular University
- Bezkoder
- Angular From Theory To Practice
- Angular in Action
- Ng-Book: The Complete Guide to Angular
- Pro Angular 6
- Beginning Angular with Typescript
- Angular 6 for Enterprise-Ready Web Applications
- ASP.NET Core 2 and Angular 5
- Angular Up & Running
- Codecraft
- Rangle.io
- Angular 2 Succinctly
- Angular2Book
- Learning Angular: A no-nonsense guide to building web applications with Angular 15, 4th Edition
- Freecodecamp
- Programming With Mosh
- Angular University
- Traversy Media
- Code With Harry
- Fireship
- Academind
- Decoded Frontend
- Brandon Roberts
- ARC Tutorials
- Edureka
- Simplilearn
- Joshua Morony
- Codevolution
- Code Step By Step
- UX Trendz
- Devstackr
- David Acosta
- Testy Codiez
- CodAffection
- Techsith
- Mosh
- Minko Gechev
- Todd Motto
- Deborah Kurata
- John Papa
- Dan Wahlin
- Maximilian Schwarzmüller
- Wes Bos
- Tracy Lee | ladyleet
- Shai Reznik
- Victor Savkin
- Stephen Fluin
- Juri Strumpflohner
- Kevin Kreuzer
- Aristeidis Bampakos
- Dmytro Mezhenskyi
- Santosh Yadav
- Tomas Trajan
- Marko Stanimirović
- Teja Gandhamu
- Santosh Yadav
- Juri Strumpflohner
- Minko Gechev
- Todd Motto
- Deborah Kurata
Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests.
This project is licensed under the MIT License - see the LICENSE file for details.
If you like this learning repository and find it useful, consider buying me a coffee or sponsoring me through the GitHub Sponsor. Your support will help me to continue and bring more exciting projects. Thank you!
Show your support by 🌟 the repository.