A computed signal holds a read-only value derived from other signals. Create one with Angular’s `computed` function and a function that returns the derived value. Read the result by calling the signal, such as `categories()`. Angular tracks the signals read during the derivation, caches the result, and recomputes it when it is next read after a dependency changes. section 10.4.2 section 5.3.3
Derive categories from products
A product repository can define `categories = computed(() => products().map(p => p.category ?? "(None)").filter((c, i, all) => all.indexOf(c) === i).sort())`. Reading `products()` establishes the dependency. Mapping, deduplication, and sorting need not run again while the products signal remains unchanged. section 5.3.3
Listing 5.13. The contents of the product.repository.ts file in the src/app/model folder
import { Injectable, Signal, computed } from "@angular/core";
import { Product } from "./product.model";
import { StaticDataSource } from "./static.datasource";
@Injectable()
export class ProductRepository {
products: Signal<Product[]>;
categories: Signal<string[]>;
constructor(private dataSource: StaticDataSource) {
this.products = dataSource.products;
this.categories = computed(() => {
return this.dataSource.products()
.map(p => p.category ?? "(None)")
.filter((c, index, array) =>
array.indexOf(c) == index).sort();
})
}
getProduct(id: number): Product | undefined {
return this.dataSource.products().find(p => p.id == id);
}
}
The repository listing places a computed category signal alongside its source product signal and shows both being read as functions. section 5.3.3
Use writable signals for choices that change and computed signals for values derived from those choices. A store component filters repository products using a selected-category signal. Changing the category invalidates the filtered result; the next read computes the appropriate products. Pagination extends the same pattern to page size, selected page, displayed products, and page numbers. section 5.5.2 section 5.5.3
Listing 11.1. Replacing the contents of the component.ts file in the src/app folder
import { Component, computed } from "@angular/core";
import { Model } from "./repository.model";
import { Product } from "./product.model";
@Component({
selector: "app",
templateUrl: "template.html"
})
export class ProductComponent {
private model: Model = new Model();
products = computed<Product[]>(() => this.model.Products());
count = computed<number>(() => this.products().length);
classes = computed<string>(() =>
this.count() == 5 ? "bg-success" : "bg-warning");
}
This compact component shows computed signals depending on other computed signals: products determine a count, which determines a CSS class. section 11.1
Keep changing inputs inside signals. If a derivation relies on an ordinary value, Angular cannot track its changes and may keep the cached result. Computed signals can also read signals exposed by a model or service; templates read their values with calls such as `count()` or `lastMessage()`. section 10.4.2 section 10.4.4 section 20.3.2

