Angular course · Module 5: Services and DI

Services in Angular - Craftsmen Guilds

1 min read ·
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/katana
Code 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. 1. Which decorator marks a class as a service in Angular?

  2. 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):

Useful articles