Angular 15, released in November 2022, introduced powerful features like standalone components, improved image directives, and better tree-shakability. This tutorial guides you through setting up Angular 15 and building a basic Todo application. We’ll cover installation, project creation, components, services, and data binding. By the end, you’ll have a functional app. Prerequisites: Basic knowledge of HTML, CSS, JavaScript, and TypeScript. Node.js (version 14 or later) installed.
Step 1: Install Angular CLI
First, install the Angular CLI globally. Open your terminal and run:
text
npm install -g @angular/cli@15
This installs version 15 specifically. Verify with ng version, which should show Angular CLI: 15.x.x and Angular: 15.x.x.
Step 2: Create a New Project
Generate a new Angular project:
text
ng new todo-app --standalone
The –standalone flag enables standalone components by default, a key Angular 15 feature that reduces boilerplate by eliminating the need for NgModules in many cases. Navigate into the project folder: cd todo-app. Start the development server: ng serve. Open http://localhost:4200 in your browser to see the default app.
Step 3: Understand Project Structure
Angular 15’s structure is streamlined. Key files:
- src/app/app.component.ts: Root component.
- src/app/app.component.html: Template.
- src/app/app.component.css: Styles.
- src/main.ts: Bootstrap file.
- angular.json: Configuration.
With standalone components, app.module.ts is optional.
Step 4: Create Components
Let’s build our Todo app. Generate a TodoList component:
text
ng generate component todo-list --standalone
This creates todo-list.component.ts with @Component({ standalone: true }). In todo-list.component.ts, add:
typescript
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-todo-list',
standalone: true,
imports: [CommonModule, FormsModule],
templateUrl: './todo-list.component.html',
styleUrls: ['./todo-list.component.css']
})
export class TodoListComponent {
todos: string[] = [];
newTodo: string = '';
addTodo() {
if (this.newTodo) {
this.todos.push(this.newTodo);
this.newTodo = '';
}
}
removeTodo(index: number) {
this.todos.splice(index, 1);
}
}
Here, we import necessary modules directly into the component—another Angular 15 perk.
In todo-list.component.html:
html
<h2>Todo List</h2>
<input [(ngModel)]="newTodo" placeholder="Add new todo">
<button (click)="addTodo()">Add</button>
<ul>
<li *ngFor="let todo of todos; let i = index">
{{ todo }} <button (click)="removeTodo(i)">Remove</button>
</li>
</ul>
This uses two-way binding with ngModel and structural directives like *ngFor.
Step 5: Integrate into App Component
Update app.component.ts to include TodoListComponent:
typescript
import { Component } from '@angular/core';
import { TodoListComponent } from './todo-list/todo-list.component';
@Component({
selector: 'app-root',
standalone: true,
imports: [TodoListComponent],
template: '<app-todo-list></app-todo-list>'
})
export class AppComponent {}
Remove the default content from app.component.html if needed.
Step 6: Add a Service for Data Persistence
For better architecture, create a service to manage todos:
text
ng generate service todo
In todo.service.ts:
typescript
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class TodoService {
private todos: string[] = [];
getTodos(): string[] {
return this.todos;
}
addTodo(todo: string) {
this.todos.push(todo);
}
removeTodo(index: number) {
this.todos.splice(index, 1);
}
}
Update todo-list.component.ts to use the service:
typescript
import { Component, inject } from '@angular/core';
import { TodoService } from '../todo.service';
// ... other imports
@Component({
// ...
})
export class TodoListComponent {
todoService = inject(TodoService);
newTodo: string = '';
get todos() {
return this.todoService.getTodos();
}
addTodo() {
if (this.newTodo) {
this.todoService.addTodo(this.newTodo);
this.newTodo = '';
}
}
removeTodo(index: number) {
this.todoService.removeTodo(index);
}
}
Angular 15’s inject() function simplifies dependency injection.
Step 7: Enhance with Routing
Add routing for scalability. Generate a Home component:
text
ng generate component home --standalone
Update app.component.ts to use RouterModule:
typescript
import { Component } from '@angular/core';
import { RouterOutlet, provideRouter } from '@angular/router';
import { bootstrapApplication } from '@angular/platform-browser';
import { routes } from './app.routes'; // Create this file
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet],
template: '<router-outlet></router-outlet>'
})
export class AppComponent {}
bootstrapApplication(AppComponent, {
providers: [provideRouter(routes)]
});
Create app.routes.ts:
typescript
import { Routes } from '@angular/router';
import { TodoListComponent } from './todo-list/todo-list.component';
import { HomeComponent } from './home/home.component';
export const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'todos', component: TodoListComponent }
];
In home.component.html, add a link: <a routerLink=”/todos”>Go to Todos</a>.
Step 8: Build and Deploy
Test with ng serve. For production: ng build –prod. The output in dist/ can be deployed to services like Vercel or GitHub Pages.
Angular 15 improves performance with automatic tree-shaking of unused code and the ngOptimizedImage directive for lazy loading images (add it to your app for practice).
