← Back to blog
Angular
Signals
Angular 19
Reactivity
TypeScript

Exploring Linked Signals in Angular 19: A New Reactive Primitive for Dynamic Applications

By Sujit Yadav7 min read
Exploring Linked Signals in Angular 19: A New Reactive Primitive for Dynamic Applications

Angular 19 introduces an experimental feature called Linked Signal, a powerful reactive primitive designed to handle dynamic data synchronization effortlessly. In this article, we'll dive into the concept of Linked Signals using a flight management system as an example, showcasing how it solves common challenges in dynamic applications.

The Problem: Dynamic Flight Selection

Imagine a Flight Selector component where users can choose a flight from a list of available options. The component has two key signals:

  1. Available Flights: a signal input providing the list of available flights.
  2. Selected Flight: a signal storing the flight selected by the user, or null if no selection is made.

Here's the challenge: if the list of available flights changes (e.g. flights are added or removed), the selected flight signal must reset if the previously selected flight is no longer valid. Additionally, we want to pre-select the first available flight by default when the list changes.

Why Existing Approaches Fall Short

The Selected Flight signal is typically initialized in the component's constructor. At this stage, the Available Flights signal has not yet been resolved, leading to two issues: the initial value of Available Flights is an empty array, and attempting to set the Selected Flight signal to the first flight in this array results in undefined, which is converted to null.

When the Available Flights signal updates later, the selection isn't synchronized because the initialization wasn't part of a reactive context. Using computed() could help, but it has limitations when the value needs to be overridden at runtime.

The Solution: Linked Signals

Linked Signals combine the benefits of reactivity and mutability. Here's how we can set up a Linked Signal for the Selected Flight:

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

@Component({
  selector: 'flight-selector',
  template: `
    <div>
      <h3>Available Flights</h3>
      <ul>
        <li *ngFor="let flight of availableFlights()">
          <button (click)="selectFlight(flight)">{{ flight }}</button>
        </li>
      </ul>
      <p>Selected Flight: {{ selectedFlight() }}</p>
    </div>
  `,
})
export class FlightSelectorComponent {
  availableFlights = signal<string[]>([]); // List of flights
  selectedFlight = linked({
    source: () => this.availableFlights(),
    compute: (flights) => (flights.length > 0 ? flights[0] : null),
  });

  selectFlight(flight: string) {
    this.selectedFlight.set(flight);
  }

  updateAvailableFlights(newFlights: string[]) {
    this.availableFlights.set(newFlights);
  }
}

Here, linked ensures that when availableFlights changes, the selectedFlight signal is recomputed. Users can override the selectedFlight value by clicking a flight, and it remains persistent until the availableFlights list changes.

Advanced Use Case: Retaining a Valid Selection

Now let's enhance the logic to retain the currently selected flight if it remains in the updated list. If the previously selected flight is no longer available, the signal resets to null.

this.selectedFlight = linked({
  source: () => this.availableFlights(),
  compute: (flights, prev) => {
    const previousSelection = prev?.value;
    return flights.includes(previousSelection) ? previousSelection : null;
  },
});

The compute function receives the previous state, allowing us to check if the previously selected flight is still valid. If valid, the previous selection is retained; otherwise, the signal resets to null.

Explicit Configuration for Clarity

Linked Signals also support a more explicit configuration format, useful for complex scenarios:

this.selectedFlight = linked<string[], string | null>({
  source: () => this.availableFlights(),
  compute: (flights, prev) => {
    const previousSelection = prev?.value;
    return flights.includes(previousSelection) ? previousSelection : null;
  },
});

By specifying generic types, string[] represents the type of the source (Available Flights) and string | null defines the type of the signal (Selected Flight). This ensures type safety when dealing with diverse data types.

Key Advantages of Linked Signals

  1. Reactive context: automatically recomputes the signal value when dependencies change.
  2. Mutability: allows overriding the signal value at runtime while retaining reactive updates.
  3. Access to previous state: provides both the previous source value and signal state, enabling advanced logic.

Summary

Linked Signals in Angular 19 offer a seamless way to handle dynamic data dependencies while preserving runtime flexibility. As this feature is still in developer preview, it's not yet ready for production — but experimenting with it now will prepare you to leverage it fully when it's officially released.

Originally published on LinkedIn — read the original article.