Angular Computed Signals: Dynamic Data Aggregation
This challenge focuses on leveraging Angular's computed signals to create reactive, derived data. You'll build a component that displays aggregated information based on underlying signal values, automatically updating as those values change. This is crucial for building dynamic user interfaces where displayed data needs to reflect complex relationships between different data points.
Problem Description
You need to create an Angular component that manages a list of products, each with a name and a price. The component should display:
- A list of all product names.
- The total price of all products.
- The average price of all products.
The key requirement is that the total price and average price should be computed signals. This means they should automatically update whenever the list of products or the prices of individual products change, without explicit manual recalculation.
Key Requirements:
- Manage a list of product objects, where each product has at least a
name(string) andprice(number). - Use Angular signals to manage the product list.
- Create a computed signal for the total price of all products.
- Create a computed signal for the average price of all products.
- Display the product names, total price, and average price in the component's template.
- Implement a mechanism to add new products to the list and observe the computed signals updating reactively.
Expected Behavior:
When the component loads, it should display the initial product list, total price, and average price. If a new product is added, the displayed total and average prices should update immediately and reflect the new product's price.
Edge Cases:
- Empty Product List: Handle the scenario where there are no products. The average price should be 0 or NaN (depending on desired behavior, 0 is preferred for UI simplicity).
- Zero Prices: Ensure calculations are correct if product prices are zero.
Examples
Example 1:
// Initial state in the component
productsSignal.set([
{ id: 1, name: 'Laptop', price: 1200 },
{ id: 2, name: 'Mouse', price: 25 }
]);
Output (in template):
Product Names: Laptop, Mouse Total Price: $1225 Average Price: $612.50
Explanation: The component initializes with two products. The total price is 1200 + 25 = 1225. The average price is 1225 / 2 = 612.50.
Example 2:
// After adding a new product
productsSignal.update(products => [
...products,
{ id: 3, name: 'Keyboard', price: 75 }
]);
Output (in template, after the update):
Product Names: Laptop, Mouse, Keyboard Total Price: $1300 Average Price: $433.33
Explanation: A new product "Keyboard" with a price of 75 is added. The total price becomes 1225 + 75 = 1300. The average price becomes 1300 / 3 = 433.33 (approximately).
Example 3: Empty Product List
// Initial state with no products
productsSignal.set([]);
Output (in template):
Product Names: (empty) Total Price: $0 Average Price: $0
Explanation: When the product list is empty, the total price should be 0, and the average price should also be 0 to avoid division by zero errors or displaying NaN.
Constraints
- The solution must be implemented in TypeScript within an Angular component.
- Angular signals (writable signals and computed signals) are mandatory for managing and deriving product data.
- Avoid manual DOM manipulation for updates; rely on Angular's reactivity.
- The product data structure should be an array of objects, each with at least
name: stringandprice: number.
Notes
- Consider how to structure your signals. A writable signal for the
productsarray is a good starting point. - Think about how to access the underlying values of signals within your computed signal logic.
- The
effectAPI can be useful for debugging or performing side effects based on signal changes, but the core requirement is computed signals for the derived values. - For displaying currency, you might consider using Angular's
currencypipe in the template for better formatting, but the calculation logic is the focus here.