DEV Community

Cristian Sifuentes
Cristian Sifuentes

Posted on

Building a Professional Angular 19 App Using Signals and Services

UsingSignalsAndServices

In this article, we will build a professional-grade example using:

  • ✅ Angular 19
  • ✅ Signals
  • ✅ Dependency Injection (Services)
  • ✅ Standalone Components

Goal

We will create:

  • A service that manages a list of heroes using signal().
  • A component that displays and adds heroes via the service.
  • Clean, reactive, and fully Angular 19-compliant code.

Setting up the Service: HeroService

import { Injectable, signal } from '@angular/core';

export interface Hero {
  id: number;
  name: string;
}

@Injectable({ providedIn: 'root' })
export class HeroService {
  private heroes = signal<Hero[]>([
    { id: 1, name: 'Goku' },
    { id: 2, name: 'Vegeta' }
  ]);

  getHeroes() {
    return this.heroes;
  }

  addHero(hero: Hero) {
    this.heroes.update(prev => [...prev, hero]);
  }

  removeHero(id: number) {
    this.heroes.update(prev => prev.filter(h => h.id !== id));
  }
}
Enter fullscreen mode Exit fullscreen mode

Building the Component: HeroListComponent

import { Component } from '@angular/core';
import { HeroService } from './hero.service';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';

@Component({
  selector: 'app-hero-list',
  standalone: true,
  template: `
    <h2>Hero List</h2>

    <ul>
      <li *ngFor="let hero of heroes()">
        {{ hero.name }}
        <button (click)="remove(hero.id)">Remove</button>
      </li>
    </ul>

    <input [(ngModel)]="newHeroName" placeholder="New hero" />
    <button (click)="add()">Add Hero</button>
  `,
  imports: [CommonModule, FormsModule]
})
export class HeroListComponent {
  heroes = signal<Hero[]>([]);
  newHeroName = '';

  constructor(private heroService: HeroService) {
    this.heroes = this.heroService.getHeroes();
  }

  add() {
    if (this.newHeroName.trim()) {
      const newHero = { id: Date.now(), name: this.newHeroName.trim() };
      this.heroService.addHero(newHero);
      this.newHeroName = '';
    }
  }

  remove(id: number) {
    this.heroService.removeHero(id);
  }
}
Enter fullscreen mode Exit fullscreen mode

How It Works

Layer Purpose
Service (HeroService) Owns the signal<Hero[]>, responsible for all state
Component (HeroListComponent) Subscribes to the signal and reacts automatically
Template Renders reactive values via heroes() call

When you call addHero() or removeHero(), the signal updates and the component auto-renders without manual refresh.


Key Best Practices

  • Services manage signals, components consume them.
  • No manual subscriptions needed.
  • Keep services pure and encapsulated.
  • Use standalone components for cleaner architecture.

Final Thoughts

Angular 19 is leading towards a lightweight, reactive, modular future. Using Signals and Services properly will make your apps:

  • Faster
  • More maintainable
  • Highly scalable

Use Signals for state, Services for management, and Standalone Components for architecture.

Happy coding with Angular 19! ⚡

Top comments (0)