Architecture Design
Introduction
Angular is a popular frontend framework for building dynamic web applications. Maintained by Google, it provides a comprehensive solution including components, templates, services, routing, and more.
Angular Overview
Angular is written in TypeScript and is a component-driven framework. It emphasizes unidirectional data flow and immutability, offering a modular, reusable component structure.
Project Setup and Basic Configuration
Installing Angular CLI:
npm install -g @angular/cliCreating a Project:
ng new my-angular-app
cd my-angular-appProject Structure:
- src/: Source code directory
- app/: Main application module and components
- assets/: Static resources
- environments/: Environment configurations
- Basic Configuration: Configure project settings in
angular.json, such as build and development server options.
Components, Templates, and Data Binding
Creating a Component:
ng generate component my-componentComponent Code:
import { Component } from '@angular/core';
@Component({
selector: 'app-my-component',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.css']
})
export class MyComponent {
title = 'Hello Angular!';
}Template Binding:
<h1>{{ title }}</h1>
<input [(ngModel)]="title" />Directives and Pipes
Built-in Directives:
*ngIf: Conditional rendering*ngFor: Iterative rendering
Custom Directive:
import { Directive, ElementRef, Renderer2 } from '@angular/core';
@Directive({
selector: '[appHighlight]'
})
export class HighlightDirective {
constructor(el: ElementRef, renderer: Renderer2) {
renderer.setStyle(el.nativeElement, 'backgroundColor', 'yellow');
}
}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).toLowerCase();
}
}Services and Dependency Injection
Creating a Service:
ng generate service my-serviceService Code:
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class MyService {
getData() {
return 'Service Data';
}
}Dependency Injection:
import { Component, OnInit } from '@angular/core';
import { MyService } from './my-service.service';
@Component({
selector: 'app-my-component',
template: '{{ data }}'
})
export class MyComponent implements OnInit {
data: string;
constructor(private myService: MyService) {}
ngOnInit() {
this.data = this.myService.getData();
}
}Routing and Navigation
Setting Up Routing:
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: '', component: HomeComponent },
{ path: 'about', component: AboutComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {}Router Links:
<a routerLink="/">Home</a>
<a routerLink="/about">About</a>
<router-outlet></router-outlet>Form Handling
Template-Driven Forms:
<form #form="ngForm" (ngSubmit)="onSubmit(form)">
<input name="name" ngModel required />
<button type="submit">Submit</button>
</form>Reactive Forms:
import { Component } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
@Component({
selector: 'app-my-form',
template: `
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<input formControlName="name" />
<button type="submit">Submit</button>
</form>
`
})
export class MyFormComponent {
form = new FormGroup({
name: new FormControl('', Validators.required)
});
onSubmit() {
console.log(this.form.value);
}
}HTTP Client
Setting Up HTTP Module:
import { HttpClientModule } from '@angular/common/http';
@NgModule({
imports: [HttpClientModule],
})
export class AppModule {}HTTP Requests:
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class DataService {
constructor(private http: HttpClient) {}
getData() {
return this.http.get('https://api.example.com/data');
}
}State Management with NgRx
Installing NgRx:
ng add @ngrx/storeSetting Up the Store:
import { Action, createReducer, on } from '@ngrx/store';
import { createAction } from '@ngrx/store';
export const increment = createAction('[Counter Component] Increment');
const _counterReducer = createReducer(0,
on(increment, state => state + 1)
);
export function counterReducer(state: number | undefined, action: Action) {
return _counterReducer(state, action);
}Using the Store:
import { Store } from '@ngrx/store';
import { Component } from '@angular/core';
import { increment } from './counter.reducer';
@Component({
selector: 'app-my-counter',
template: `
<button (click)="increment()">Increment</button>
<div>Current Count: {{ count$ | async }}</div>
`
})
export class MyCounterComponent {
count$ = this.store.select('count');
constructor(private store: Store<{ count: number }>) {}
increment() {
this.store.dispatch(increment());
}
}Performance Optimization and Best Practices
Lazy Loading Modules:
const routes: Routes = [
{ path: '', loadChildren: () => import('./home/home.module').then(m => m.HomeModule) }
];Using OnPush Change Detection:
import { Component, ChangeDetectionStrategy } from '@angular/core';
@Component({
selector: 'app-my-component',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `...`
})
export class MyComponent {}Unit and Integration Testing
Unit Testing:
import { TestBed } from '@angular/core/testing';
import { MyComponent } from './my-component.component';
describe('MyComponent', () => {
beforeEach(() => TestBed.configureTestingModule({ declarations: [MyComponent] }));
it('should create the component', () => {
const fixture = TestBed.createComponent(MyComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
});Integration Testing:
import { TestBed, fakeAsync, tick } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './app.component';
import { Router } from '@angular/router';
describe('AppComponent', () => {
let router: Router;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule.withRoutes([])],
declarations: [AppComponent]
});
router = TestBed.inject(Router);
});
it('should navigate to "home" on click', fakeAsync(() => {
router.navigate(['/home']);
tick();
expect(router.url).toBe('/home');
}));
});Deployment and Release
Production Build:
ng build --prodDeploy to Server: Upload the dist folder to a server (e.g., Apache, Nginx) or host on platforms like Firebase or Netlify.



