Angular is a TypeScript-based open-source web framework for building dynamic single-page applications.
Installation
Prerequisites
# Install Node.js 18+ and npm
node --version
npm --version
# Install Angular CLI globally
npm install -g @angular/cli
# Verify installation
ng version
Project Setup
| Command | Description |
|---|
ng new app-name | Create new Angular project |
ng new app-name --routing | Create with routing module |
ng new app-name --style=scss | Create with SCSS support |
cd app-name && npm start | Navigate and start dev server |
Development Server
# Start development server
ng serve
# Start on specific port
ng serve --port 4300
# Open in browser automatically
ng serve --open
# Enable source maps for debugging
ng serve --source-map
# Production build preview
ng serve --configuration production
Code Generation
Generate Components
# Create a new component
ng generate component components/header
# Create component with routing
ng generate component pages/home --routing
# Create component without spec file
ng generate component components/button --skip-tests
# Shorthand
ng g c components/footer
Generate Services
# Create service
ng generate service services/auth
# Create with HTTP client
ng generate service services/api
# Shorthand
ng g s services/user
Generate Other Modules
# Create module
ng generate module modules/shared
# Create with routing
ng generate module modules/admin --routing
# Create guard
ng generate guard guards/auth
# Create interceptor
ng generate interceptor interceptors/http
# Create pipe
ng generate pipe pipes/safe-html
# Create directive
ng generate directive directives/highlight
# Create interface
ng generate interface models/user
Building
| Command | Description |
|---|
ng build | Build for development |
ng build --configuration production | Build for production |
ng build --output-hashing all | Hash all output files |
ng build --source-map=false | Disable source maps (smaller size) |
Testing
# Run unit tests
ng test
# Run tests with coverage
ng test --code-coverage
# Run tests with watch disabled
ng test --watch=false
# Run e2e tests
ng e2e
# Run specific test file
ng test --include='**/header.component.spec.ts'
Common Angular Patterns
Component with Dependency Injection
import { Component, OnInit } from '@angular/core';
import { AuthService } from '../services/auth.service';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss']
})
export class HeaderComponent implements OnInit {
user$ = this.authService.getCurrentUser();
constructor(private authService: AuthService) {}
ngOnInit(): void {
this.authService.checkAuth();
}
logout(): void {
this.authService.logout();
}
}
Service with HTTP
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { User } from '../models/user';
@Injectable({
providedIn: 'root'
})
export class UserService {
private apiUrl = '/api/users';
constructor(private http: HttpClient) {}
getUsers(): Observable<User[]> {
return this.http.get<User[]>(this.apiUrl);
}
getUser(id: string): Observable<User> {
return this.http.get<User>(`${this.apiUrl}/${id}`);
}
createUser(user: User): Observable<User> {
return this.http.post<User>(this.apiUrl, user);
}
updateUser(id: string, user: User): Observable<User> {
return this.http.put<User>(`${this.apiUrl}/${id}`, user);
}
deleteUser(id: string): Observable<void> {
return this.http.delete<void>(`${this.apiUrl}/${id}`);
}
}
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-contact-form',
template: `
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<input formControlName="email" type="email">
<textarea formControlName="message"></textarea>
<button type="submit" [disabled]="form.invalid">Send</button>
</form>
`
})
export class ContactFormComponent implements OnInit {
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
email: ['', [Validators.required, Validators.email]],
message: ['', [Validators.required, Validators.minLength(10)]]
});
}
ngOnInit(): void {}
onSubmit(): void {
if (this.form.valid) {
console.log(this.form.value);
}
}
}
Routing Configuration
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './pages/home/home.component';
import { AboutComponent } from './pages/about/about.component';
import { NotFoundComponent } from './pages/not-found/not-found.component';
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'about', component: AboutComponent },
{ path: 'admin', loadChildren: () => import('./modules/admin/admin.module').then(m => m.AdminModule) },
{ path: '**', component: NotFoundComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {}
Hooks and Lifecycle
| Hook | Purpose |
|---|
ngOnInit | Initialize component after Angular creates it |
ngOnChanges | Respond to changes in @Input properties |
ngDoCheck | Detect changes Angular can’t detect |
ngAfterViewInit | Initialize component view and child views |
ngOnDestroy | Cleanup before Angular destroys component |
Directives
<!-- Structural directives -->
<div *ngIf="isVisible">Conditional content</div>
<div *ngFor="let item of items">{{ item }}</div>
<div [ngSwitch]="status">
<span *ngSwitchCase="'active'">Active</span>
<span *ngSwitchDefault>Inactive</span>
</div>
<!-- Attribute directives -->
<div [ngClass]="{ active: isActive, disabled: isDisabled }">Classes</div>
<div [ngStyle]="{ color: textColor, 'font-size': fontSize }">Styles</div>
<!-- Two-way binding -->
<input [(ngModel)]="username">
<!-- Property binding -->
<img [src]="imageUrl">
<!-- Event binding -->
<button (click)="handleClick()">Click me</button>
<!-- Attribute binding -->
<button [attr.aria-label]="buttonLabel">Button</button>
Decorators
| Decorator | Purpose |
|---|
@Component | Define component metadata |
@Directive | Define directive metadata |
@Injectable | Mark class as service |
@Input | Declare input property |
@Output | Declare output event |
@ViewChild | Get reference to DOM element |
@NgModule | Define module metadata |
Dependency Injection
@Injectable({
providedIn: 'root' // Available application-wide
})
export class MyService {
constructor() {}
}
// In module
@NgModule({
providers: [MyService] // Available in this module
})
export class AppModule {}
// In component
constructor(private service: MyService) {}
Observables and RxJS
// Create observable
import { Observable } from 'rxjs';
import { map, filter, take } from 'rxjs/operators';
const data$ = this.http.get('/api/data').pipe(
map(data => data.items),
filter(items => items.length > 0),
take(1)
);
// Subscribe
data$.subscribe({
next: (data) => console.log(data),
error: (err) => console.error(err),
complete: () => console.log('Done')
});
// Using async pipe in template
<div>{{ data$ | async }}</div>
Module Structure
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ReactiveFormsModule } from '@angular/forms';
import { MyComponent } from './my.component';
@NgModule({
declarations: [MyComponent],
imports: [CommonModule, ReactiveFormsModule],
exports: [MyComponent]
})
export class MyModule {}
Debugging
# Enable Angular DevTools debugging
ng serve --configuration development
# View production-like bundle analysis
ng build --stats-json
npx webpack-bundle-analyzer dist/app/stats.json
Environment Configuration
// environment.ts (development)
export const environment = {
production: false,
apiUrl: 'http://localhost:3000'
};
// environment.prod.ts (production)
export const environment = {
production: true,
apiUrl: 'https://api.example.com'
};
# Enable lazy loading
ng generate module modules/dashboard --routing
# Analyze bundle size
ng build --stats-json
# Production build
ng build --configuration production --optimization
Common Configuration Changes
angular.json
{
"projects": {
"my-app": {
"architect": {
"build": {
"options": {
"outputPath": "dist/my-app",
"index": "src/index.html",
"main": "src/main.ts"
}
}
}
}
}
}
Best Practices
- Use OnPush change detection for performance
- Implement OnDestroy to unsubscribe from observables
- Use trackBy function with ngFor for lists
- Lazy load feature modules
- Use strict TypeScript mode
- Keep components focused on single responsibility
- Use services for shared logic
- Use RxJS operators correctly
- Implement proper error handling
- Test components and services thoroughly
Useful CLI Flags
| Flag | Purpose |
|---|
--skip-tests | Skip creating spec files |
--skip-install | Skip npm install |
--routing | Include routing module |
--style=scss | Use SCSS for styles |
--strict | Enable strict mode |
--package-manager=npm | Use npm (default) |
Resources
Last updated: 2026-03-30|Angular 17+