Angular is a robust, TypeScript-based framework widely used for building dynamic, scalable, and maintainable web applications. One of its defining features is its component-based architecture, which organizes the application into modular, reusable pieces. Understanding Angular’s architecture is critical for developers who want to build large-scale, maintainable applications.
In this article, we will explore Angular’s architecture in detail. We will cover components, modules, services, dependency injection, templates, data binding, and best practices. We will also provide code examples for practical understanding.
1. Introduction to Angular Architecture
Angular architecture is designed to provide a structured and maintainable way to develop web applications. At its core, Angular uses a component-based architecture, where each part of the user interface is built as a reusable component.
Key principles of Angular architecture:
- Modularity: Break your app into smaller, manageable parts.
- Reusability: Components can be reused across different parts of the app.
- Testability: Services and components can be tested independently.
- Maintainability: Modules organize components, services, and other features systematically.
Angular applications generally consist of:
- Components: Define the UI and behavior.
- Modules: Group related components and services.
- Services: Provide shared logic and data access.
- Templates: Define HTML structure with data binding.
- Dependency Injection: Angular’s mechanism to provide services to components.
- Routing: Navigate between different views.
2. Components: Building Blocks of Angular
Components are the foundation of Angular applications. Each component controls a part of the UI and encapsulates its template, styles, and behavior.
2.1 Component Structure
A component consists of:
- TypeScript class: Contains logic and data.
- Template: HTML view for the UI.
- Styles: CSS or SCSS for styling.
Example:
import { Component } from '@angular/core';
@Component({
selector: 'app-header',
template: <h1>{{ title }}</h1>
,
styles: [h1 { color: navy; }
]
})
export class HeaderComponent {
title = 'Welcome to Angular Architecture';
}
2.2 Creating Components
Angular CLI makes it simple to generate components:
ng generate component header
This creates:
header.component.ts
– Component logicheader.component.html
– HTML templateheader.component.css
– Stylesheader.component.spec.ts
– Unit test
2.3 Component Interaction
Components can communicate through:
- Input and Output Decorators
- Event Emitters
Example of parent-child communication:
// child.component.ts
import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-child',
template: <button (click)="notifyParent()">Click Me</button>
})
export class ChildComponent {
@Input() message: string = '';
@Output() clicked = new EventEmitter<string>();
notifyParent() {
this.clicked.emit(this.message);
}
}
<!-- parent.component.html -->
<app-child [message]="'Hello Parent!'" (clicked)="handleClick($event)"></app-child>
// parent.component.ts
handleClick(event: string) {
console.log('Child says:', event);
}
3. Modules: Organizing Angular Applications
Modules are used to organize related components, services, and other features. The main module of an Angular application is the AppModule
.
3.1 AppModule
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { HeaderComponent } from './header/header.component';
@NgModule({
declarations: [AppComponent, HeaderComponent],
imports: [BrowserModule],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
3.2 Feature Modules
For large applications, feature modules help separate concerns:
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { UserListComponent } from './user-list/user-list.component';
@NgModule({
declarations: [UserListComponent],
imports: [CommonModule],
exports: [UserListComponent]
})
export class UserModule {}
3.3 Shared Modules
Shared modules contain components, directives, or pipes that are reused across multiple modules.
@NgModule({
declarations: [CustomPipe, HighlightDirective],
imports: [CommonModule],
exports: [CustomPipe, HighlightDirective]
})
export class SharedModule {}
4. Services: Sharing Logic and Data
Services are singleton classes used to share logic and data across components. Angular uses Dependency Injection to provide services where needed.
4.1 Creating a Service
ng generate service data
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class DataService {
private users = ['Alice', 'Bob', 'Charlie'];
getUsers() {
return this.users;
}
}
4.2 Injecting a Service
import { Component, OnInit } from '@angular/core';
import { DataService } from './data.service';
@Component({
selector: 'app-user',
template: <ul><li *ngFor="let user of users">{{ user }}</li></ul>
})
export class UserComponent implements OnInit {
users: string[] = [];
constructor(private dataService: DataService) {}
ngOnInit() {
this.users = this.dataService.getUsers();
}
}
5. Dependency Injection in Angular
Dependency Injection (DI) is a design pattern where components declare dependencies, and Angular provides them automatically.
Example
constructor(private logger: LoggerService, private http: HttpClient) {}
Benefits of DI:
- Reusable services
- Decoupled components
- Easier testing
6. Templates and Data Binding
Templates define the HTML structure and bind data from components using Angular’s binding mechanisms.
6.1 Interpolation
<h1>{{ title }}</h1>
6.2 Property Binding
<img [src]="imageUrl" />
6.3 Event Binding
<button (click)="handleClick()">Click Me</button>
6.4 Two-Way Binding
<input [(ngModel)]="name" />
<p>Hello, {{ name }}</p>
7. Angular Directives
Directives are special instructions in templates that modify DOM behavior.
- Structural Directives:
*ngIf
,*ngFor
- Attribute Directives:
ngClass
,ngStyle
Example:
<div *ngIf="isVisible">Visible Content</div>
<ul>
<li *ngFor="let user of users">{{ user }}</li>
</ul>
<p [ngStyle]="{color: 'red'}">Styled Text</p>
8. Angular Routing
Angular uses the RouterModule for navigation between views.
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'about', component: AboutComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {}
<a routerLink="/">Home</a>
<a routerLink="/about">About</a>
<router-outlet></router-outlet>
9. Angular Lifecycle Hooks
Angular components have lifecycle hooks to handle specific stages:
ngOnInit
: Initialize datangOnChanges
: Handle input changesngDoCheck
: Custom change detectionngOnDestroy
: Cleanup resources
Example:
ngOnInit() { console.log('Component initialized'); }
ngOnDestroy() { console.log('Component destroyed'); }
10. Best Practices for Angular Architecture
- Use modular architecture: Separate features into modules.
- Keep components small and reusable.
- Use services for shared logic.
- Implement lazy loading for large apps.
- Follow naming conventions for consistency.
- Use Angular CLI for project scaffolding.
- Leverage TypeScript for type safety.
- Optimize change detection with OnPush strategy.
- Write unit tests for components and services.
- Use shared modules for reusable pipes and directives.
11. Real-World Example: Modular Angular App
Imagine a simple e-commerce app with the following structure:
app/
app.module.ts
header/
header.component.ts
products/
products.module.ts
product-list.component.ts
product-detail.component.ts
users/
users.module.ts
user-list.component.ts
- HeaderComponent: Common UI for all pages
- ProductsModule: Handles product-related components
- UsersModule: Manages user-related features
Leave a Reply