A data source supplies application data without requiring the rest of the application to know where that data originates. It may initially return in-memory products and later obtain them through HTTP. Keeping that choice behind a data source makes the change easier to manage. section 5.3.2 section 9.6.1
A typical model separates three jobs: a descriptive class defines a product, a data source loads or saves data, and a repository gives application features access to it. The repository mediates access so components do not need to handle the details of obtaining data. section 9.6.1 section 5.3.3
Listing 9.20. The contents of the datasource.model.ts file in the src/app folder
import { Product } from "./product.model";
export class SimpleDataSource {
private data: Product[];
constructor() {
this.data = new Array<Product>(
new Product(1, "Kayak", "Watersports", 275),
new Product(2, "Lifejacket", "Watersports", 48.95),
new Product(3, "Soccer Ball", "Soccer", 19.50),
new Product(4, "Corner Flags", "Soccer", 34.95),
new Product(5, "Thinking Cap", "Chess", 16));
}
getData(): Product[] {
return this.data;
}
}
This in-memory implementation stores Product objects and returns them through getData(). It is enough to develop against before adding server requests. section 9.6.1
The repository can read those products, find one by ID, and expose operations for changing the model. In a signal-based version, a static data source exposes Signal<Product[]>; the repository reads it by calling products() and derives a category list with computed(). That derived list is recalculated when the product signal changes. section 5.3.3 section 9.6.1
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 receives StaticDataSource through its constructor, exposes its product signal, and derives categories without making components depend directly on the source. section 5.3.3
For server-backed data, register RestDataSource and HttpClientModule, then update repositories to use the new source. HTTP results arrive as observables; toSignal converts a product observable to the signal expected by the repository, with an empty array as its initial value. Order saving can delegate to the REST source and retain an observable result. This swap changes model-layer wiring rather than requiring the rest of the application to know the data’s origin. section 6.6.1 section 23.3.2
Do not confuse the model’s data-source service with the “data source” in *ngFor syntax*. In `*ngFor="let item of products()"`, the term means the collection being enumerated to produce template rows, not the service that loaded the products. section 12.2.3












