What is Angular?
Angular is a powerful TypeScript-based open-source framework developed by Google for building single-page applications (SPAs). It provides a rich set of features including components, services, dependency injection, routing, and more.
Setting Up Angular
Prerequisites
- Node.js and npm (Node Package Manager)
- Angular CLI
Installation
# Install Angular CLI globally
npm install -g @angular/cli
# Create a new Angular project
ng new my-angular-app
# Start the development server
ng serve
Core Concepts
1. Components
Components are the building blocks of Angular applications.
Component Structure
// app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<h1>{{ title }}</h1>
<p>{{ description }}</p>
`
})
export class AppComponent {
title = 'My Angular App';
description = 'Welcome to Angular!';
}
Creating a New Component
ng generate component my-component
# or
ng g c my-component
2. Data Binding
One-way Data Binding
// Component
export class DataBindingComponent {
message = 'Hello Angular!';
}
<!-- Template -->
<h1>{{message}}</h1>
Two-way Data Binding
// Component
export class DataBindingComponent {
name = '';
}
<!-- Template -->
<input [(ngModel)]="name">
<p>Hello, {{name}}!</p>
3. Directives
Built-in Directives
ngIf
<div *ngIf="isVisible">
This content is conditionally displayed
</div>
ngFor
<ul>
<li *ngFor="let item of items; let i = index">
{{i + 1}}. {{item}}
</li>
</ul>
ngSwitch
<div [ngSwitch]="color">
<p *ngSwitchCase="'red'">Red</p>
<p *ngSwitchCase="'blue'">Blue</p>
<p *ngSwitchDefault>Default</p>
</div>
Custom Directive
// highlight.directive.ts
import { Directive, ElementRef } from '@angular/core';
@Directive({
selector: '[appHighlight]'
})
export class HighlightDirective {
constructor(el: ElementRef) {
el.nativeElement.style.backgroundColor = 'yellow';
}
}
4. Services and Dependency Injection
Creating a Service
// data.service.ts
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class DataService {
getData() {
return ['Item 1', 'Item 2', 'Item 3'];
}
}
Using the Service
// component.ts
import { Component } from '@angular/core';
import { DataService } from './data.service';
@Component({
selector: 'app-data',
template: `
<ul>
<li *ngFor="let item of items">{{item}}</li>
</ul>
`
})
export class DataComponent {
items: string[];
constructor(private dataService: DataService) {
this.items = this.dataService.getData();
}
}
5. Forms
Template-Driven Forms
// Component
export class UserFormComponent {
user = {
name: '',
email: ''
};
onSubmit() {
console.log(this.user);
}
}
<!-- Template -->
<form #userForm="ngForm" (ngSubmit)="onSubmit()">
<div>
<label>Name:</label>
<input [(ngModel)]="user.name" name="name" required>
</div>
<div>
<label>Email:</label>
<input [(ngModel)]="user.email" name="email" required email>
</div>
<button type="submit" [disabled]="!userForm.valid">Submit</button>
</form>
Reactive Forms
// Component
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
export class ReactiveFormComponent {
userForm: FormGroup;
constructor(private fb: FormBuilder) {
this.userForm = this.fb.group({
name: ['', Validators.required],
email: ['', [Validators.required, Validators.email]]
});
}
onSubmit() {
if (this.userForm.valid) {
console.log(this.userForm.value);
}
}
}
<!-- Template -->
<form [formGroup]="userForm" (ngSubmit)="onSubmit()">
<div>
<label>Name:</label>
<input formControlName="name">
</div>
<div>
<label>Email:</label>
<input formControlName="email">
</div>
<button type="submit" [disabled]="!userForm.valid">Submit</button>
</form>
6. HTTP Client
Making HTTP Requests
// service.ts
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class ApiService {
constructor(private http: HttpClient) {}
getData() {
return this.http.get('https://api.example.com/data');
}
postData(data: any) {
return this.http.post('https://api.example.com/data', data);
}
}
7. Routing
Basic Routing Setup
// app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home.component';
import { AboutComponent } from './about.component';
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'about', component: AboutComponent },
{ path: '**', redirectTo: '' }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Router Navigation
<!-- Template -->
<nav>
<a routerLink="/">Home</a>
<a routerLink="/about">About</a>
</nav>
<router-outlet></router-outlet>
8. Lifecycle Hooks
import { Component, OnInit, OnDestroy } from '@angular/core';
@Component({
selector: 'app-lifecycle',
template: '<p>{{data}}</p>'
})
export class LifecycleComponent implements OnInit, OnDestroy {
data: string = '';
ngOnInit() {
console.log('Component initialized');
this.data = 'Initialized data';
}
ngOnDestroy() {
console.log('Component destroyed');
}
}
Best Practices
1. Project Structure
src/
├── app/
│ ├── components/
│ ├── services/
│ ├── models/
│ └── shared/
├── assets/
└── environments/
2. Performance Tips
- Use OnPush change detection strategy
- Lazy load modules
- Use trackBy with ngFor
- Minimize subscription memory leaks
3. Error Handling
// Global error handler
import { ErrorHandler, Injectable } from '@angular/core';
@Injectable()
export class GlobalErrorHandler implements ErrorHandler {
handleError(error: Error) {
console.error('An error occurred:', error);
// Log to server or show user-friendly message
}
}
4. Testing
// Component test
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MyComponent } from './my.component';
describe('MyComponent', () => {
let component: MyComponent;
let fixture: ComponentFixture<MyComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ MyComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(MyComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Example Application
Here’s a simple todo list application showcasing various Angular features:
// todo.component.ts
import { Component } from '@angular/core';
interface Todo {
id: number;
text: string;
completed: boolean;
}
@Component({
selector: 'app-todo',
template: `
<div class="todo-app">
<h1>Todo List</h1>
<form (ngSubmit)="addTodo()">
<input [(ngModel)]="newTodoText"
name="newTodo"
placeholder="Add new todo">
<button type="submit">Add</button>
</form>
<ul>
<li *ngFor="let todo of todos">
<input type="checkbox"
[(ngModel)]="todo.completed">
<span [class.completed]="todo.completed">
{{todo.text}}
</span>
<button (click)="deleteTodo(todo.id)">Delete</button>
</li>
</ul>
<div class="stats">
Completed: {{completedCount}} / {{todos.length}}
</div>
</div>
`,
styles: [`
.completed {
text-decoration: line-through;
}
`]
})
export class TodoComponent {
todos: Todo[] = [];
newTodoText = '';
get completedCount() {
return this.todos.filter(todo => todo.completed).length;
}
addTodo() {
if (this.newTodoText.trim()) {
this.todos.push({
id: Date.now(),
text: this.newTodoText,
completed: false
});
this.newTodoText = '';
}
}
deleteTodo(id: number) {
this.todos = this.todos.filter(todo => todo.id !== id);
}
}
Deployment
To deploy your Angular application:
# Create production build
ng build --prod
# The built files will be in the dist/ folder
# Deploy these files to your web server
Remember to always check the official Angular documentation for the most up-to-date information and features.