Angular course · Module 5: Services and DI
Services in Angular - Craftsmen Guilds
In this lesson3
Services in Angular are like craftsmen guilds - specialized units providing services to the entire kingdom. Each guild has its specialization: blacksmiths forge swords, tailors sew kimonos.
What is a Service?
A Service is a class responsible for:
- Business logic - calculations, validations
- API communication - fetching/sending data
- State management - storing data between components
- Code sharing - avoiding duplication
Creating a Service
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root' // Singleton available throughout the application
})
export class KatanaService {
private katanas: Katana[] = [];
getAll(): Katana[] {
return [...this.katanas]; // We return a copy
}
getById(id: number): Katana | undefined {
return this.katanas.find(k => k.id === id);
}
forge(name: string, type: string): Katana {
const katana: Katana = {
id: Date.now(),
name,
type,
damage: Math.floor(Math.random() * 100) + 50,
createdAt: new Date()
};
this.katanas.push(katana);
return katana;
}
destroy(id: number): boolean {
const index = this.katanas.findIndex(k => k.id === id);
if (index > -1) {
this.katanas.splice(index, 1);
return true;
}
return false;
}
}Generating via CLI
ng generate service services/katana
# or shorter:
ng g s services/katanaCode for this lesson: src/app/app.component.ts
import { Component, inject } from '@angular/core';
import { SamuraiService } from './services/samurai.service';
import { LoggerService } from './services/logger.service';
@Component({
selector: 'app-root',
standalone: true,
template: `
<div class="guild-hall">
<header>
<h1>Craftsmen Guild</h1>
<p>Module 5: Services and Dependency Injection</p>
</header>
<main>
<section class="info-panel">
<h2>About Services</h2>
<p>Services are craftsmen guilds - specialists for specific tasks.</p>
<ul>
<li>@Injectable() - registration in DI</li>
<li>providedIn: 'root' - singleton</li>
<li>inject() - modern injection</li>
</ul>
</section>
<section class="demo-panel">
<h2>Samurai List (from Service)</h2>
<div class="samurai-list">
@for (s of samuraiList; track s.id) {
<div class="samurai-card">
<strong>{{ s.name }}</strong>
<span>Clan: {{ s.clan }}</span>
<span>Level: {{ s.level }}</span>
</div>
}
</div>
<div class="actions">
<button (click)="addSamurai()">Add Samurai</button>
<button (click)="showLogs()">Show Logs</button>
</div>
</section>
<section class="logs-panel" *ngIf="logs.length">
<h3>Logs (from LoggerService)</h3>
<ul>
@for (log of logs; track $index) {
<li>{{ log }}</li>
}
</ul>
</section>
</main>
</div>
`,
styles: [`
.guild-hall {
font-family: 'Segoe UI', sans-serif;
max-width: 900px;
margin: 0 auto;
padding: 20px;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
min-height: 100vh;
color: #eee;
}
header {
text-align: center;
border-bottom: 2px solid #c9a227;
padding-bottom: 20px;
}
h1, h2, h3 { color: #c9a227; }
.info-panel, .demo-panel, .logs-panel {
background: rgba(255,255,255,0.05);
border: 1px solid #c9a227;
border-radius: 8px;
padding: 20px;
margin: 20px 0;
}
ul { list-style: none; padding: 0; }
li::before { content: "» "; }
.samurai-card {
background: #16213e;
border: 1px solid #333;
border-radius: 8px;
padding: 15px;
margin: 10px 0;
display: flex;
justify-content: space-between;
}
.actions {
display: flex;
gap: 10px;
margin-top: 15px;
}
button {
background: #c9a227;
color: #1a1a2e;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
}
button:hover { opacity: 0.9; }
.logs-panel ul {
background: #0d1117;
padding: 15px;
border-radius: 4px;
font-family: monospace;
font-size: 0.9rem;
}
.logs-panel li::before { content: "› "; color: #4ade80; }
`]
})
export class AppComponent {
private samuraiService = inject(SamuraiService);
private logger = inject(LoggerService);
samuraiList = this.samuraiService.getAll();
logs: string[] = [];
addSamurai() {
const newSamurai = {
id: Date.now(),
name: 'New Warrior',
clan: 'Ronin',
level: 1
};
this.samuraiService.add(newSamurai);
this.samuraiList = this.samuraiService.getAll();
this.logger.log('Added new samurai: ' + newSamurai.name);
}
showLogs() {
this.logs = this.logger.getLogs();
}
}Docs entries used in this lesson
Spotted a mistake in this lesson?
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. Which decorator marks a class as a service in Angular?
2. According to the lesson, what is a Service responsible for in Angular?
These are 2 of 3 questions for this lesson. Solve the rest in the game.
Hands-on tasks in the game
- Horizontal ordering
Arrange the import of the Injectable decorator on one line:
- Code editor
Complete SamuraiService so that Angular can inject it and creates one shared instance for the whole application.
- Click in order
Build the Angular CLI command that generates a service (click in order):