Angular v20 Made Eazy
1. Introduction to Angular
What is Angular?
Angular is a powerful, open-source front-end web application framework developed and maintained by Google. It allows developers to build scalable, modular, and high-performance web applications using HTML, CSS, and TypeScript. Angular uses a component-based architecture and supports modern features such as two-way data binding, dependency injection, and reactive programming.
Why Angular? Features & Benefits
- Component-Based Architecture: Simplifies UI development and promotes code reusability.
- TypeScript: Offers static typing and advanced tooling for improved development experience.
- Dependency Injection: Manages services efficiently and promotes maintainable code.
- RxJS & Observables: Supports reactive programming for asynchronous data handling.
- Built-in Routing: Provides seamless navigation and lazy loading of modules.
- CLI Tooling: The Angular CLI accelerates development with commands for creating, building, and testing applications.
Understanding Angular Architecture
Angular is based on a modular architecture consisting of components, directives, services, and modules. At its core:
- Modules: Organize application functionality into cohesive blocks.
- Components: Control views (HTML) and logic (TypeScript) for each part of the UI.
- Templates: Define the HTML structure using Angular directives and expressions.
- Services: Handle business logic and data access, often shared across components.
- Dependency Injection: Automatically provides services to components where needed.
- Routing: Allows navigation between components with defined paths.
2. Setting Up the Development Environment
Installing Node.js and Angular CLI
To begin developing Angular applications, you need to install Node.js (which includes npm – Node Package Manager) and Angular CLI.
- Download and install Node.js from nodejs.org.
- Once installed, open a terminal and verify installation:
node -v
npm -v
Now install Angular CLI globally using npm:
npm install -g @angular/cli
Verify Angular CLI installation:
ng version
Creating Your First Angular App
Use the Angular CLI to create a new application:
ng new my-first-app
The CLI will prompt you for options like routing and stylesheets. Choose your preferences.
Navigate to the app directory and serve the app:
cd my-first-app
ng serve
Visit http://localhost:4200
in your browser to view your Angular application running locally.
Angular CLI Commands and Project Structure
Angular CLI helps generate code and manage your project efficiently.
ng generate component component-name
— Creates a new component.ng generate service service-name
— Creates a new service.ng build
— Compiles the project for deployment.ng test
— Runs unit tests.ng lint
— Analyzes the code for style and errors.
Typical Angular folder structure:
src/
┣ app/
┃ ┣ components/
┃ ┣ services/
┃ ┗ app.module.ts
┣ assets/
┗ index.html
3. Components and Templates
Creating Components using CLI
Components are the core building blocks of Angular applications. You can generate them using the Angular CLI:
ng generate component component-name
Component Metadata and Decorators
Each component is a class annotated with the @Component
decorator which provides metadata that Angular uses to create and display the component.
import { Component } from '@angular/core';
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent {
title = 'Hello Angular';
}
Data Binding – Interpolation, Property & Event Binding
- Interpolation: Embed dynamic content using
{{ expression }}
- Property Binding: Bind data from class to view with
[property]
- Event Binding: Capture user actions with
(event)
<h1>{{ title }}</h1>
<img [src]="imageUrl" />
<button (click)="onClick()">Click Me</button>
Two-way Binding with ngModel
Two-way binding keeps the input field and component in sync. Import FormsModule
and use:
<input [(ngModel)]="userName" />
<p>Welcome, {{ userName }}</p>
Component Interaction using @Input() and @Output()
Pass data from parent to child using @Input()
and from child to parent using @Output()
with EventEmitter
.
// child.component.ts
@Input() item: string;
@Output() notify = new EventEmitter();
sendMessage() {
this.notify.emit('Message from child');
}
// parent.component.html
<app-child [item]="parentData" (notify)="handleNotify($event)"></app-child>
4. Directives and Pipes
Built-in Structural Directives: *ngIf, *ngFor
Structural directives change the structure of the DOM. Examples include:
<div *ngIf="isVisible">Conditionally visible</div>
<ul>
<li *ngFor="let item of items">{{ item }}</li>
</ul>
Attribute Directives: ngClass, ngStyle
Attribute directives modify the appearance or behavior of elements:
<div [ngClass]="{ 'highlight': isActive }">Styled Div</div>
<div [ngStyle]="{ 'color': color, 'font-size': fontSize + 'px' }">Styled Text</div>
Creating Custom Directives
To create your own directive:
ng generate directive highlight
Example directive to change background color:
import { Directive, ElementRef, HostListener } from '@angular/core';
@Directive({
selector: '[appHighlight]'
})
export class HighlightDirective {
constructor(private el: ElementRef) {
el.nativeElement.style.backgroundColor = 'yellow';
}
}
Using Built-in Pipes
Pipes are used to transform output in templates:
{{ birthday | date:'longDate' }}
{{ amount | currency:'USD' }}
{{ user | json }}
Creating Custom Pipes
ng generate pipe capitalize
Example custom pipe:
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'capitalize'
})
export class CapitalizePipe implements PipeTransform {
transform(value: string): string {
return value.charAt(0).toUpperCase() + value.slice(1);
}
}
Usage: {{ 'angular' | capitalize }}
5. Services and Dependency Injection
Creating a Service with Angular CLI
Services are used to share data and functionality across components. You can generate a service using:
ng generate service data
Injecting Services into Components
Services are injected via the constructor of a component:
constructor(private dataService: DataService) {}
ngOnInit() {
this.items = this.dataService.getItems();
}
Using providedIn: 'root'
This registers the service globally without needing to import it in a module's providers array:
@Injectable({
providedIn: 'root'
})
export class DataService {
getItems() {
return ['Item1', 'Item2'];
}
}
Hierarchical Injection
You can scope a service to a specific module or component to create a new instance for that context. For example:
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
providers: [ScopedService]
})
export class ChildComponent {
constructor(private scopedService: ScopedService) {}
}
Each instance of this component will get a new instance of ScopedService
.
6. Routing and Navigation
Setting Up Routing Module
Angular provides a built-in router that enables navigation between different components. You can configure routes in a routing module.
const routes: Routes = [
{ path: 'home', component: HomeComponent },
{ path: 'about', component: AboutComponent },
{ path: '', redirectTo: '/home', pathMatch: 'full' },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {}
RouterOutlet and RouterLink
<router-outlet>
acts as a placeholder that Angular dynamically fills based on the current route. Use routerLink
directive for navigation.
<nav>
<a routerLink="/home">Home</a>
<a routerLink="/about">About</a>
</nav>
<router-outlet></router-outlet>
Route Parameters and Query Strings
You can pass dynamic values through route parameters:
{ path: 'product/:id', component: ProductComponent }
In the component:
constructor(private route: ActivatedRoute) {}
ngOnInit() {
const id = this.route.snapshot.paramMap.get('id');
}
Query strings can be accessed with:
this.route.queryParams.subscribe(params => {
console.log(params['search']);
});
Child Routes and Lazy Loading
Nested routing allows embedding routes within other components. Lazy loading improves performance by loading modules only when needed.
const routes: Routes = [
{
path: 'admin',
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
}
];
Route Guards: AuthGuard and CanActivate
Guards restrict access to routes based on conditions such as authentication.
canActivate(): boolean {
return this.authService.isLoggedIn();
}
Apply in route:
{
path: 'dashboard',
component: DashboardComponent,
canActivate: [AuthGuard]
}
7. HTTPClient and REST API Integration
Using HttpClientModule
Angular provides the HttpClientModule
in @angular/common/http
to make HTTP requests.
// app.module.ts
import { HttpClientModule } from '@angular/common/http';
@NgModule({
imports: [HttpClientModule]
})
export class AppModule {}
GET, POST, PUT, DELETE Requests
constructor(private http: HttpClient) {}
// GET
getUsers() {
return this.http.get('https://api.example.com/users');
}
// POST
createUser(user: any) {
return this.http.post('https://api.example.com/users', user);
}
// PUT
updateUser(id: number, user: any) {
return this.http.put(`https://api.example.com/users/${id}`, user);
}
// DELETE
deleteUser(id: number) {
return this.http.delete(`https://api.example.com/users/${id}`);
}
Error Handling with catchError
You can handle HTTP errors using RxJS catchError
operator.
import { catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';
getData() {
return this.http.get('/api/data').pipe(
catchError(error => {
console.error('Error:', error);
return throwError(() => new Error('Something went wrong'));
})
);
}
Handling Observables and Subscriptions
this.http.get('/api/data').subscribe({
next: data => this.data = data,
error: err => console.error('Error occurred:', err),
complete: () => console.log('Request complete')
});
Always unsubscribe to avoid memory leaks when not using async pipe.
ngOnDestroy() {
this.subscription.unsubscribe();
}
8. Forms in Angular
Template-Driven Forms
Template-driven forms are defined directly in the template using Angular directives like ngModel
. Suitable for simple forms.
// app.module.ts
import { FormsModule } from '@angular/forms';
@NgModule({
imports: [FormsModule]
})
export class AppModule {}
Reactive Forms
Reactive forms are built in the component class using FormGroup
and FormControl
. Suitable for complex forms.
// app.module.ts
import { ReactiveFormsModule } from '@angular/forms';
@NgModule({
imports: [ReactiveFormsModule]
})
export class AppModule {}
// app.component.ts
form = new FormGroup({
email: new FormControl('', [Validators.required, Validators.email])
});
FormGroup, FormControl, Validators
FormGroup
is a collection of controls. FormControl
tracks the value and validation status of individual form elements. Validators enforce rules like required or email.
this.form = new FormGroup({
name: new FormControl('', Validators.required),
email: new FormControl('', [Validators.required, Validators.email])
});
Form Validation and Error Messages
You can check for validation errors and show helpful messages to users.
Email is required.
Invalid email format.
9. Angular Modules
Understanding NgModules
NgModules are containers that group components, directives, pipes, and services that are related. They help organize code into cohesive blocks and manage dependencies.
// app.module.ts
@NgModule({
declarations: [AppComponent, MyComponent],
imports: [BrowserModule, FormsModule],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
Shared and Feature Modules
Shared modules contain reusable components, directives, and pipes. Feature modules group functionality by specific domains (e.g., ProductsModule).
// shared.module.ts
@NgModule({
declarations: [SharedComponent],
exports: [SharedComponent],
imports: [CommonModule]
})
export class SharedModule {}
// products.module.ts
@NgModule({
declarations: [ProductListComponent],
imports: [CommonModule, SharedModule]
})
export class ProductsModule {}
Lazy Loading Modules
Lazy loading is a technique where modules are loaded on demand. This improves initial load performance.
// app-routing.module.ts
const routes: Routes = [
{
path: 'products',
loadChildren: () => import('./products/products.module').then(m => m.ProductsModule)
}
];
10. Build and Deployment
Building Angular Application
Use the Angular CLI to build the production-ready version of your app. It optimizes and compiles TypeScript code into efficient JavaScript.
ng build --configuration production
Optimizing the Build
- Use AOT (Ahead-of-Time) compilation (enabled by default in production build)
- Enable build optimizer and minification
- Remove unused dependencies and dead code
ng build --configuration production --base-href=/my-app/
Deploying to GitHub Pages
- Install angular-cli-ghpages
npm install -g angular-cli-ghpages
ng deploy --base-href=/my-app/
Deploying to Firebase Hosting
npm install -g firebase-tools
firebase login
firebase init
ng build --configuration production
firebase deploy
Deploying to Netlify
Drag and drop the contents of dist/
folder to Netlify UI or link your GitHub repo for automatic deployment.
- Set build command:
ng build --configuration production
- Set publish directory:
dist/my-app