Skip to content

Instantly share code, notes, and snippets.

@eladcandroid
Created October 29, 2025 11:45
Show Gist options
  • Save eladcandroid/22b5b281ed146d43c193adc2fef79f1c to your computer and use it in GitHub Desktop.
Save eladcandroid/22b5b281ed146d43c193adc2fef79f1c to your computer and use it in GitHub Desktop.
Angular linkedSignal Example
import { Component, linkedSignal, signal } from '@angular/core';
interface ShippingMethod {
id: number;
name: string;
}
@Component({
selector: 'app-root',
template: `
<div class="container">
<h1>Linked Signal Demo - Shipping Selection</h1>
<div class="section">
<h2>Currently Selected Option</h2>
<div class="selected-box">
<strong>ID:</strong> {{ selectedOption().id }} <br />
<strong>Name:</strong> {{ selectedOption().name }}
</div>
</div>
<div class="section">
<h2>Available Shipping Methods</h2>
<div class="options-list">
@for (option of shippingOptions(); track option.id) {
<div
class="option-card"
[class.active]="option.id === selectedOption().id"
(click)="changeShipping(shippingOptions().indexOf(option))"
>
<span class="option-id">ID: {{ option.id }}</span>
<span class="option-name">{{ option.name }}</span>
@if (option.id === selectedOption().id) {
<span class="badge">Selected</span>
}
</div>
}
</div>
</div>
<div class="section">
<h2>Actions</h2>
<button (click)="changeShippingOptions()" class="btn">Change Shipping Options</button>
<p class="info">
<em
>Note: Clicking this will update the options list. If your selected option still exists
(by ID), it will be preserved.</em
>
</p>
</div>
</div>
`,
styles: [
`
.container {
max-width: 800px;
margin: 2rem auto;
padding: 2rem;
font-family: system-ui, -apple-system, sans-serif;
}
h1 {
color: #1976d2;
margin-bottom: 2rem;
}
.section {
margin-bottom: 2rem;
padding: 1.5rem;
background: #f5f5f5;
border-radius: 8px;
}
h2 {
margin-top: 0;
color: #333;
font-size: 1.2rem;
}
.selected-box {
background: white;
padding: 1rem;
border-radius: 4px;
border-left: 4px solid #1976d2;
font-size: 1.1rem;
}
.options-list {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.option-card {
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem;
background: white;
border-radius: 4px;
cursor: pointer;
transition: all 0.2s;
border: 2px solid transparent;
}
.option-card:hover {
transform: translateX(4px);
border-color: #1976d2;
}
.option-card.active {
background: #e3f2fd;
border-color: #1976d2;
font-weight: 600;
}
.option-id {
color: #666;
font-size: 0.9rem;
min-width: 50px;
}
.option-name {
flex: 1;
font-size: 1rem;
}
.badge {
background: #1976d2;
color: white;
padding: 0.25rem 0.75rem;
border-radius: 12px;
font-size: 0.85rem;
}
.btn {
background: #1976d2;
color: white;
border: none;
padding: 0.75rem 1.5rem;
border-radius: 4px;
cursor: pointer;
font-size: 1rem;
transition: background 0.2s;
}
.btn:hover {
background: #1565c0;
}
.info {
margin-top: 1rem;
color: #666;
font-size: 0.9rem;
}
.debug {
background: #263238;
color: #aed581;
}
.debug h3 {
color: #fff;
margin-top: 0;
}
.debug pre {
margin: 0;
white-space: pre-wrap;
font-family: 'Courier New', monospace;
font-size: 0.9rem;
}
`,
],
})
export class App {
constructor() {
// this.changeShipping(2);
// this.changeShippingOptions();
// console.log(this.selectedOption()); // {"id":2,"name":"Postal Service"}
}
shippingOptions = signal<ShippingMethod[]>([
{ id: 0, name: 'Ground' },
{ id: 1, name: 'Air' },
{ id: 2, name: 'Sea' },
]);
selectedOption = linkedSignal(() => this.shippingOptions()[0]);
// selectedOption = linkedSignal<ShippingMethod[], ShippingMethod>({
// source: this.shippingOptions,
// computation: (newOptions, previous) => {
// return newOptions.find((opt) => opt.id === previous?.value.id) ?? newOptions[0];
// },
// });
changeShipping(index: number) {
this.selectedOption.set(this.shippingOptions()[index]);
}
changeShippingOptions() {
this.shippingOptions.set([
{ id: 0, name: 'Email' },
{ id: 1, name: 'Sea' },
{ id: 2, name: 'Postal Service' },
]);
}
debugInfo() {
return JSON.stringify(
{
totalOptions: this.shippingOptions().length,
options: this.shippingOptions(),
selected: this.selectedOption(),
},
null,
2
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment