Reactive Data Synchronization with withLatestFrom in Angular
withLatestFrom is a powerful operator in RxJS that allows you to combine the latest values from multiple Observables. This challenge focuses on implementing a scenario where you need to display a product's details alongside a dynamically updated discount percentage, demonstrating how withLatestFrom can synchronize data from different sources within an Angular component. Understanding this pattern is crucial for building reactive and responsive user interfaces.
Problem Description
You are building an Angular component that displays product information. The product details (name, description, price) are fetched from one Observable (product$). A separate Observable (discountPercentage$) emits the latest discount percentage, which is updated periodically (e.g., due to promotions). You need to display both the product details and the current discount percentage on the screen. The discount percentage should be applied to the product's price to calculate and display the discounted price.
Your task is to implement the Angular component using withLatestFrom to combine the latest values from product$ and discountPercentage$. The component should display the product name, description, original price, and the discounted price. When either the product details or the discount percentage changes, the displayed information should update accordingly.
Key Requirements:
- Fetch product details from an Observable named
product$. This Observable will emit an object withname,description, andpriceproperties. - Fetch discount percentage from an Observable named
discountPercentage$. This Observable will emit a number representing the discount percentage (e.g., 0.1 for 10%). - Use
withLatestFromto combine the latest values fromproduct$anddiscountPercentage$. - Calculate the discounted price by applying the discount percentage to the product's price.
- Display the product name, description, original price, and discounted price in the component's template.
- Handle the case where either
product$ordiscountPercentage$is initially empty (no data).
Expected Behavior:
- Initially, the component should display a loading indicator or a message indicating that the data is being fetched.
- Once both
product$anddiscountPercentage$emit values, the component should display the product details and the discounted price. - Whenever
product$emits a new product, the component should update the displayed product details and recalculate the discounted price. - Whenever
discountPercentage$emits a new discount percentage, the component should recalculate the discounted price and update the display. - If either Observable emits an error, the component should display an error message.
Examples
Example 1:
product$ = of({ name: 'Laptop', description: 'Powerful laptop for work and play', price: 1200 });
discountPercentage$ = of(0.1); // 10% discount
Output:
Product Name: Laptop
Description: Powerful laptop for work and play
Original Price: $1200
Discounted Price: $1080
Explanation: The product price is reduced by 10%, resulting in a discounted price of $1080.
Example 2:
product$ = of({ name: 'Smartphone', description: 'Latest smartphone model', price: 800 });
discountPercentage$ = of(0.25); // 25% discount
Output:
Product Name: Smartphone
Description: Latest smartphone model
Original Price: $800
Discounted Price: $600
Explanation: The product price is reduced by 25%, resulting in a discounted price of $600.
Example 3: (Edge Case - Initial Empty Values)
product$ = of({ name: 'Tablet', description: 'Portable tablet device', price: 300 }).pipe(delay(2000)); // Delayed emission
discountPercentage$ = of(0.05); // 5% discount
Output (Initially):
Loading...
Output (After 2 seconds):
Product Name: Tablet
Description: Portable tablet device
Original Price: $300
Discounted Price: $285
Explanation: The component initially displays "Loading..." because product$ is delayed. After 2 seconds, the product details and discounted price are displayed.
Constraints
- The
product$Observable should emit an object withname(string),description(string), andprice(number) properties. - The
discountPercentage$Observable should emit a number representing the discount percentage (between 0 and 1). - The component should be implemented using Angular's reactive forms or template-driven forms (though forms are not strictly required for this problem).
- The component should handle potential errors from either Observable gracefully.
- The solution should be concise and readable.
Notes
- Consider using the
asyncpipe in your template to subscribe to the combined Observable. - Think about how to handle the initial state where either
product$ordiscountPercentage$might not have emitted a value yet. A loading indicator or placeholder content is a good approach. withLatestFromonly emits when both Observables have emitted at least one value. This is important to remember when dealing with initial states.- You can use
ofto simulate Observables for testing purposes. In a real application, you would fetch data from an API or other data source.