Introduction to Angular
Angular is a comprehensive, opinionated framework for building single-page client applications using HTML, CSS, and TypeScript. It's maintained by Google and is used by many large enterprises for building robust web applications.
Angular History and Evolution
- AngularJS (Angular 1.x): Released in 2010, was a JavaScript-based framework that introduced two-way data binding and MVC architecture to frontend development
- Angular 2: Released in 2016, was a complete rewrite using TypeScript, with a component-based architecture and improved performance
- Angular 4+ and beyond: After Angular 2, the team moved to semantic versioning with major releases every 6 months (version 3 was skipped)
- Latest Version: Angular is currently at version 17+ (as of early 2025), with continued focus on performance, developer experience, and modern web features
When people refer to "Angular" today, they're talking about Angular 2+ (the modern versions), not AngularJS.
Real-world analogy: If AngularJS (1.x) was like building a house with traditional construction methods, modern Angular is like building with a standardized, prefabricated system. While the end result might look similar, the modern approach provides better tools, more consistent patterns, and a more structured development process.
Key Features of Angular
Angular provides a comprehensive solution with many built-in features:
TypeScript-First Approach
Angular is built with TypeScript and encourages its use, providing:
- Strong typing for better tooling and error checking
- Modern JavaScript features with backward compatibility
- Enhanced IDE support with autocomplete and refactoring tools
- Better maintainability for large codebases
Component-Based Architecture
Angular applications are built from components:
- Components encapsulate templates, logic, and styles
- Components can be nested and reused throughout the application
- Clear separation between the view (template) and the behavior (component class)
Comprehensive Tooling
Angular CLI (Command Line Interface) provides:
- Project scaffolding and application bootstrapping
- Development server with hot reloading
- Build optimization for production
- Testing infrastructure
- Code generation for components, services, etc.
Dependency Injection
A core feature that:
- Enables component reusability and testability
- Manages service instantiation and lifecycle
- Allows services to be shared across components
- Makes testing easier through service mocking
Reactive Programming Support
Angular integrates with RxJS:
- Handles asynchronous operations with Observables
- Enables complex event processing and data transformations
- Manages application state and component communication
Comprehensive Routing
Built-in router for single-page applications:
- Client-side navigation without page reloads
- Lazy loading of modules for better performance
- Route guards for controlling navigation
- Deep linking and route parameters
Form Handling
Two approaches to forms:
- Template-driven forms: simpler, HTML-first approach
- Reactive forms: more robust approach with explicit form control objects
- Comprehensive validation system
HTTP Client
Built-in service for communicating with APIs:
- Observable-based API calls
- Interceptors for request/response transformation
- Testing features for HTTP requests
Core Angular Concepts
Modules
Angular organizes the application into cohesive blocks of functionality called NgModules:
- Every Angular app has at least one module (the root module, usually called AppModule)
- Modules declare components, services, pipes, and directives
- Modules can import other modules and export their functionality
- Feature modules help organize code into functional areas
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { AppComponent } from './app.component';
import { ProductListComponent } from './products/product-list.component';
import { ProductService } from './products/product.service';
@NgModule({
imports: [ // Other modules whose exported classes are needed by component templates
BrowserModule,
FormsModule,
HttpClientModule
],
declarations: [ // Components, directives, and pipes that belong to this module
AppComponent,
ProductListComponent
],
providers: [ // Services that will be available to the entire application
ProductService
],
bootstrap: [ // The main application view, called the root component
AppComponent
]
})
export class AppModule { }
Components
Components are the building blocks of Angular applications:
- Define views with their associated logic and data
- Include a TypeScript class, an HTML template, and optional CSS styles
- Usually organized in a hierarchical structure
// product-list.component.ts
import { Component, OnInit } from '@angular/core';
import { Product } from './product.model';
import { ProductService } from './product.service';
@Component({
selector: 'app-product-list', // Used in HTML to represent this component
templateUrl: './product-list.component.html', // The HTML template
styleUrls: ['./product-list.component.css'] // The component-specific styles
})
export class ProductListComponent implements OnInit {
products: Product[] = [];
selectedProduct: Product | null = null;
constructor(private productService: ProductService) { }
ngOnInit(): void {
this.getProducts();
}
getProducts(): void {
this.productService.getProducts()
.subscribe(products => this.products = products);
}
selectProduct(product: Product): void {
this.selectedProduct = product;
}
}
Templates
Templates define the component's view in HTML, enhanced with Angular's template syntax:
- Data binding: connecting component properties to the view
- Directives: adding behavior to DOM elements
- Pipes: transforming data for display
<!-- product-list.component.html -->
<div class="product-list">
<h2>Products</h2>
<div *ngIf="products.length === 0" class="no-data">
No products found.
</div>
<ul *ngIf="products.length > 0">
<li *ngFor="let product of products"
[class.selected]="product === selectedProduct"
(click)="selectProduct(product)">
<span class="name">{{product.name}}</span>
<span class="price">{{product.price | currency}}</span>
</li>
</ul>
<div *ngIf="selectedProduct" class="product-details">
<h3>{{selectedProduct.name | uppercase}} Details</h3>
<div>ID: {{selectedProduct.id}}</div>
<div>
<label for="product-name">Name: </label>
<input id="product-name" [(ngModel)]="selectedProduct.name" placeholder="name">
</div>
</div>
</div>
Services
Services encapsulate non-UI logic and data shared across components:
- Handle data fetching and processing
- Provide communication with backend APIs
- Share functionality across different parts of the application
- Injected into components through dependency injection
// product.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, catchError, tap, of } from 'rxjs';
import { Product } from './product.model';
@Injectable({
providedIn: 'root' // Makes the service available throughout the application
})
export class ProductService {
private productsUrl = 'api/products'; // URL to web API
constructor(private http: HttpClient) { }
getProducts(): Observable<Product[]> {
return this.http.get<Product[]>(this.productsUrl)
.pipe(
tap(_ => console.log('fetched products')),
catchError(this.handleError<Product[]>('getProducts', []))
);
}
getProduct(id: number): Observable<Product> {
const url = `${this.productsUrl}/${id}`;
return this.http.get<Product>(url)
.pipe(
tap(_ => console.log(`fetched product id=${id}`)),
catchError(this.handleError<Product>('getProduct'))
);
}
private handleError<T>(operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
console.error(`${operation} failed: ${error.message}`);
// Let the app keep running by returning an empty result
return of(result as T);
};
}
}
Angular Architecture
The Angular architecture creates a clear separation of concerns while maintaining efficiency:
Module Organization
A typical Angular application organizes modules as follows:
- Root Module (AppModule): The main module that bootstraps the application
- Feature Modules: Modules for specific functional areas (e.g., Products, Admin, User)
- Shared Module: Common components, directives, and pipes shared across features
- Core Module: Singleton services and other features loaded once (auth, logging, etc.)
Component Hierarchy
Components form a tree structure, with data flowing down from parent to child:
- Root Component (AppComponent): The main application shell
- Feature Components: Main components for each section of the application
- Shared Components: Reusable UI elements used across features
- Page Components: Components representing entire pages or views
- UI Components: Smaller, more focused components for specific UI elements
Service Architecture
Services follow a layered approach:
- Data Services: Communicate with APIs and handle data retrieval/storage
- Feature Services: Implement business logic for specific features
- Utility Services: Provide shared functionality like logging or formatting
- State Management Services: Handle application state (may use NgRx or similar libraries)
Real-world analogy: Angular's architecture is like a well-designed city. Modules are like districts, each with a specific purpose. Components are like buildings, each with its own structure and function. Services are like utilities (water, electricity) that provide essential functionality across the city. The router is like the road system connecting everything together.
Data Flow and Binding
Angular offers several ways to connect component data to the template:
One-Way Data Binding
- Interpolation:
{{ expression }}- Displays component data in the template - Property Binding:
[property]="expression"- Sets an element property to a component value - Attribute Binding:
[attr.attribute]="expression"- Sets an attribute value - Class Binding:
[class.className]="expression"- Adds/removes a CSS class - Style Binding:
[style.property]="expression"- Sets an inline style
Event Binding
(event)="handler()" - Listens for DOM events and calls component methods in response
Two-Way Binding
[(ngModel)]="property" - Combines property binding and event binding for form controls
<!-- Different types of data binding -->
<!-- Interpolation -->
<h1>{{title}}</h1>
<p>Welcome, {{user.name}}!</p>
<!-- Property binding -->
<img [src]="product.imageUrl" [alt]="product.name">
<button [disabled]="isLoading">Submit</button>
<!-- Event binding -->
<button (click)="onSave()">Save</button>
<input (input)="onInput($event)">
<!-- Two-way binding (requires FormsModule) -->
<input [(ngModel)]="username">
<!-- Class and style binding -->
<div [class.active]="isActive" [style.color]="textColor">
Dynamic styling
</div>
Directives
Directives are classes that add behavior to elements in Angular templates. There are three types:
Components
Components are directives with a template (the most common type we've already discussed).
Structural Directives
These change the DOM layout by adding or removing elements:
- *ngIf: Conditionally includes a template based on an expression
- *ngFor: Repeats a template for each item in an array
- *ngSwitch: Switches between alternative templates based on a condition
<!-- ngIf example -->
<div *ngIf="user.isAdmin">Admin content here</div>
<!-- ngFor example -->
<ul>
<li *ngFor="let item of items; let i = index; trackBy: trackByFn">
{{i}}: {{item.name}}
</li>
</ul>
<!-- ngSwitch example -->
<div [ngSwitch]="userRole">
<div *ngSwitchCase="'admin'">Admin content</div>
<div *ngSwitchCase="'editor'">Editor content</div>
<div *ngSwitchDefault>User content</div>
</div>
Attribute Directives
These change the appearance or behavior of an existing element:
- ngClass: Adds/removes multiple CSS classes
- ngStyle: Sets multiple inline styles
- ngModel: Adds two-way data binding to form elements
<!-- ngClass example -->
<div [ngClass]="{'active': isActive, 'disabled': isDisabled}">
Dynamic classes
</div>
<!-- ngStyle example -->
<div [ngStyle]="{'color': textColor, 'font-size': fontSize + 'px'}">
Dynamic styling
</div>
<!-- ngModel example -->
<input [(ngModel)]="username" placeholder="Username">
Custom Directives
You can create your own directives for specific behaviors:
// highlight.directive.ts
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
@Directive({
selector: '[appHighlight]'
})
export class HighlightDirective {
@Input('appHighlight') highlightColor = '';
@Input() defaultColor = 'yellow';
constructor(private el: ElementRef) { }
@HostListener('mouseenter') onMouseEnter() {
this.highlight(this.highlightColor || this.defaultColor);
}
@HostListener('mouseleave') onMouseLeave() {
this.highlight('');
}
private highlight(color: string) {
this.el.nativeElement.style.backgroundColor = color;
}
}
// Usage in template
<p appHighlight="lightblue" defaultColor="pink">
Hover over me
</p>
Pipes
Pipes transform data for display in templates without modifying the original values:
Built-in Pipes
- DatePipe:
{{ date | date:'short' }}- Formats dates - UpperCasePipe:
{{ name | uppercase }}- Converts text to uppercase - LowerCasePipe:
{{ name | lowercase }}- Converts text to lowercase - CurrencyPipe:
{{ price | currency:'USD' }}- Formats currencies - DecimalPipe:
{{ number | number:'1.2-2' }}- Formats numbers - PercentPipe:
{{ value | percent:'2.2-2' }}- Formats percentages - JsonPipe:
{{ object | json }}- Converts to JSON string - SlicePipe:
{{ array | slice:1:3 }}- Returns a slice of an array - AsyncPipe:
{{ observable | async }}- Subscribes to an Observable or Promise
Chaining Pipes
Pipes can be chained for multiple transformations:
{{ birthday | date:'fullDate' | uppercase }}
Custom Pipes
You can create custom pipes for application-specific transformations:
// truncate.pipe.ts
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'truncate'
})
export class TruncatePipe implements PipeTransform {
transform(value: string, limit = 25, completeWords = false, ellipsis = '...') {
if (!value) {
return '';
}
if (value.length <= limit) {
return value;
}
if (completeWords) {
limit = value.substring(0, limit).lastIndexOf(' ');
}
return `${value.substring(0, limit)}${ellipsis}`;
}
}
// Usage in template
<p>{{ longText | truncate:50:true }}</p>
Angular CLI
The Angular CLI is a command-line tool that makes Angular development easier:
Installation
npm install -g @angular/cli
Creating a New Project
ng new my-angular-app
Common Commands
- ng serve: Starts the development server
- ng build: Compiles the application for production
- ng test: Runs unit tests
- ng e2e: Runs end-to-end tests
- ng generate component: Generates a new component
- ng generate service: Generates a new service
- ng generate module: Generates a new module
- ng update: Updates Angular dependencies
Generating Code
// Generate a component
ng generate component products/product-list
// or the shorthand
ng g c products/product-list
// Generate a service
ng generate service products/product
// or the shorthand
ng g s products/product
// Generate a module
ng generate module products --routing
// or the shorthand
ng g m products --routing
// Generate other artifacts
ng g directive shared/highlight
ng g pipe shared/truncate
ng g class models/product
ng g interface models/product
ng g enum models/product-category
Each generation command creates the necessary files with boilerplate code, saving development time and ensuring consistent patterns.
Project Structure
A typical Angular project (created with the CLI) has the following structure:
my-angular-app/
├── src/ # Source code of the application
│ ├── app/ # Application components, templates, and logic
│ │ ├── app.component.ts # Root component logic
│ │ ├── app.component.html # Root component template
│ │ ├── app.component.css # Root component styles
│ │ ├── app.component.spec.ts # Root component tests
│ │ ├── app.module.ts # Root module
│ │ ├── app-routing.module.ts # Application routes
│ │ ├── core/ # Core module for single-use components and services
│ │ ├── shared/ # Shared module for commonly used components
│ │ └── features/ # Feature modules (products, orders, etc.)
│ ├── assets/ # Static assets like images, fonts, etc.
│ ├── environments/ # Environment-specific configuration
│ ├── index.html # Main HTML file
│ ├── main.ts # Entry point of the application
│ ├── polyfills.ts # Browser polyfills
│ ├── styles.css # Global styles
│ └── test.ts # Testing configuration
├── node_modules/ # Dependencies
├── angular.json # Angular CLI configuration
├── package.json # NPM package configuration
├── tsconfig.json # TypeScript configuration
├── karma.conf.js # Karma test runner configuration
└── README.md # Project documentation
This structure follows Angular best practices and provides a solid foundation for scaling applications.
Comparing Angular with Other Frameworks
Angular vs React
| Feature | Angular | React |
|---|---|---|
| Type | Full framework | Library |
| Language | TypeScript-first | JavaScript with optional TypeScript |
| Learning Curve | Steeper | Moderate |
| Style | Opinionated | Flexible |
| DOM Manipulation | Real DOM with change detection | Virtual DOM |
| State Management | Services, RxJS, NgRx | React Context, Redux, MobX |
| Tooling | Comprehensive CLI | Create React App, but more options |
Angular vs Vue
| Feature | Angular | Vue |
|---|---|---|
| Type | Full framework | Progressive framework |
| Language | TypeScript-first | JavaScript with optional TypeScript |
| Learning Curve | Steeper | Gentle |
| Style | Opinionated | Flexible but with conventions |
| Component Structure | Separate files for logic, template, styles | Single-file components |
| Reactivity System | Zone.js change detection | Proxy-based reactivity |
| State Management | Services, RxJS, NgRx | Vuex, Pinia |
When to Choose Angular
Angular is particularly well-suited for:
- Large enterprise applications
- Teams that prefer a standardized, opinionated framework
- Applications that benefit from strong typing and robust tooling
- Complex applications with sophisticated state management needs
- Teams already familiar with TypeScript
- Projects requiring long-term maintenance and scalability
Real-world examples of companies using Angular:
- Google (Gmail, Google Cloud Console)
- Microsoft (Office 365)
- IBM
- Delta Airlines
- Samsung
- Deutsche Bank
Practice Activity
Setting Up Your First Angular Application
- Install the Angular CLI globally:
npm install -g @angular/cli - Create a new Angular application:
ng new my-first-angular-appDuring setup, choose:
- Add Angular routing? Yes
- Which stylesheet format? CSS
- Navigate to the project directory:
cd my-first-angular-app - Start the development server:
ng serve --open - Generate your first component:
ng generate component dashboard - Modify the app.component.html file to include your dashboard component
- Create a simple dashboard with cards showing different metrics
Challenge Tasks
- Generate a service to provide data to your dashboard:
ng generate service services/data - Add methods to the service that return different types of data
- Inject the service into your dashboard component
- Use *ngFor to display multiple cards based on the data
- Add a button to each card that toggles detailed information
- Use pipes to format dates and numbers in your dashboard
Key Takeaways
- Angular is a comprehensive TypeScript-based framework for building web applications
- The core architectural elements are modules, components, services, and templates
- Angular provides powerful data binding capabilities for connecting components to templates
- Directives and pipes enable template manipulation and data transformation
- The Angular CLI simplifies project setup and code generation
- Angular is particularly suited for large enterprise applications and teams
- Angular provides a complete solution with routing, forms, HTTP, and more built-in
- TypeScript integration offers enhanced tooling and type safety