In the evolving world of Angular Signals, linkedSignal is a specialized tool introduced to solve a specific, frustrating problem: How do I have a Signal that can be updated manually, but also "resets" automatically when another Signal changes?
Before linkedSignal (introduced as an experimental feature in Angular v18.2/19, stable in v20), achieving this required messy workarounds using effect or ngOnChanges.
How linkedSignal Works
A linkedSignal is a Writable Signal that is "linked" to a source signal. It behaves like a normal signal (you can .set() it), but it has a built-in "reset" trigger.
Basic Syntax
import { signal, linkedSignal } from '@angular/core';
const shippingOptions = signal(['Standard', 'Express', 'Overnight']);
// This signal is linked to shippingOptions
const selectedOption = linkedSignal(() => shippingOptions()[0]);
// 1. User can change it manually
selectedOption.set('Express');
// 2. If shippingOptions changes, selectedOption resets to the first item automatically!
shippingOptions.set(['Drone', 'Teleport']);
// selectedOption() is now 'Drone'
Two Ways to Use It
1. Shorthand (Basic Reset)
If you just want the signal to reset to a specific value whenever the source changes, you pass a "computation" function.
const count = signal(0);
const message = linkedSignal(() => `Count is currently ${count()}`);
2. Full Configuration (Custom Reset Logic)
Sometimes you don't just want to reset to a value; you want to decide how to reset based on the previous value.
const options = linkedSignal({
source: this.shippingOptions,
computation: (newOptions, previous) => {
// Logic to decide the new value
return newOptions.includes(previous?.value)
? previous.value
: newOptions[0];
}
});
When using the
previousparameter, it is necessary to provide the generic type arguments oflinkedSignalexplicitly. The first generic type corresponds with the type ofsourceand the second generic type determines the output type ofcomputation.
Why is it better than an effect?
Before linkedSignal, developers often did this:
// THE OLD, MESSY WAY
effect(() => {
const source = this.sourceSignal();
untracked(() => {
this.writableSignal.set(source); // Manual sync is prone to bugs and loops
});
});
Custom equality comparison
linkedSignal, as any other signal, can be configured with a custom equality function. This function is used by downstream dependencies to determine if that value of the linkedSignal (result of a computation) changed:
const activeUser = signal({id: 123, name: 'Morgan', isAdmin: true});
const activeUserEditCopy = linkedSignal(() => activeUser(), {
// Consider the user as the same if it's the same `id`.
equal: (a, b) => a.id === b.id,
});
// Or, if separating `source` and `computation`
const activeUserEditCopy = linkedSignal({
source: activeUser,
computation: (user) => user,
equal: (a, b) => a.id === b.id,
});
When should you use it?
Use linkedSignal whenever you have Derived State that must remain editable.
Forms: Resetting a "Current Email" field when the "Selected User" changes.
Pagination: Resetting the "Current Page" to 1 when the "Search Query" changes.
Default Values: A "Settings" toggle that defaults to a value from the server but can be overriden by the user.
Code Playground
Hope this helps. Happy coding!!!
References
Top comments (0)