Tutorial: Real-Time Stock Tracker with Angular + WebSockets + Signals

April 2025

In this tutorial, we’ll build a real-time stock price tracker using Angular’s new Signals API combined with WebSockets for live data feeds. This app will showcase how fine-grained reactivity in Angular 18 can help you efficiently update UI elements as data streams in, without costly change detection cycles.


Why Use Signals with WebSockets?

WebSockets push live data from the server to the client continuously. Angular’s Signals let us react to these updates granularly—only updating components or UI parts that really need it, resulting in snappy and performant apps.


Step 1: Setting Up the Angular Project

Create a new Angular 18 project:

ng new stock-tracker --routing --style=scss
cd stock-tracker

Install any needed dependencies for WebSocket support (we’ll use native WebSocket in this tutorial).


Step 2: Creating a StockService to Handle WebSocket Connections

We’ll create a service that connects to a WebSocket server sending stock price updates.

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

interface StockPrice {
  symbol: string;
  price: number;
  timestamp: number;
}

@Injectable({ providedIn: 'root' })
export class StockService {
  private socket!: WebSocket;

  // Signal to hold the latest prices mapped by symbol
  public prices = signal<Record<string, StockPrice>>({});

  connect(url: string) {
    this.socket = new WebSocket(url);

    this.socket.onmessage = (event) => {
      const data: StockPrice = JSON.parse(event.data);

      // Update the prices signal reactively
      this.prices.update(currentPrices => ({
        ...currentPrices,
        [data.symbol]: data
      }));
    };

    this.socket.onerror = (error) => {
      console.error('WebSocket error:', error);
    };
  }

  disconnect() {
    this.socket.close();
  }
}

Step 3: Building the Stock List Component

This component subscribes to prices and renders a live-updating table.

import { Component, OnInit, OnDestroy } from '@angular/core';
import { StockService } from './stock.service';

@Component({
  selector: 'app-stock-list',
  template: `
    <h2>Real-Time Stock Prices</h2>
    <table>
      <thead>
        <tr><th>Symbol</th><th>Price</th><th>Last Updated</th></tr>
      </thead>
      <tbody>
        <tr *ngFor="let stock of stockSymbols">
          <td>{{stock}}</td>
          <td>{{ prices()[stock]?.price | currency:'USD' }}</td>
          <td>{{ prices()[stock]?.timestamp | date:'shortTime' }}</td>
        </tr>
      </tbody>
    </table>
  `
})
export class StockListComponent implements OnInit, OnDestroy {
  prices = this.stockService.prices;
  stockSymbols: string[] = ['AAPL', 'GOOGL', 'MSFT', 'TSLA'];

  constructor(private stockService: StockService) {}

  ngOnInit() {
    this.stockService.connect('wss://example.com/stocks');
  }

  ngOnDestroy() {
    this.stockService.disconnect();
  }
}

Step 4: Running and Testing

Start your app:

ng serve

With the WebSocket server sending JSON updates like:

{ "symbol": "AAPL", "price": 172.35, "timestamp": 1680000000000 }

You’ll see the stock prices update live as data arrives.


Step 5: Bonus – Adding Filtering or Sorting

You can easily extend this example by adding reactive signals for filtering or sorting the stocks list, enhancing the UX without extra change detection overhead.


Summary

This tutorial demonstrated:

  • How to use Angular’s Signals for reactive state management.
  • Connecting to WebSocket streams for real-time data.
  • Building a performant, live-updating stock tracker UI.

Angular 18’s fine-grained reactivity combined with WebSockets unlocks powerful patterns for building responsive real-time apps.


Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *