Dynamic Product Filtering in an Angular E-commerce App
This challenge requires you to implement a robust filtering mechanism for a list of products in an Angular application. This is a fundamental feature for any e-commerce platform, allowing users to quickly narrow down their choices based on various criteria, improving user experience and conversion rates.
Problem Description
You are tasked with building a product listing component in Angular that displays a list of products. Users should be able to filter this list dynamically based on several criteria: product category, price range, and availability (in stock or out of stock).
Key Requirements:
- Display Products: The component should fetch and display a list of products. Each product should have at least the following properties:
id(number),name(string),category(string),price(number), andinStock(boolean). - Filtering Controls: Implement UI controls (e.g., dropdowns, checkboxes, sliders) for users to select filtering criteria.
- Category Filter: A dropdown or multi-select to choose one or more product categories.
- Price Range Filter: A mechanism to specify a minimum and maximum price (e.g., two input fields or a range slider).
- Availability Filter: A checkbox or toggle to filter for products that are
inStock.
- Dynamic Filtering: As users interact with the filtering controls, the displayed product list should update in real-time to show only products that match all selected criteria.
- Clear Filters: Provide a button to reset all filters and display the full product list.
- No External Libraries (for filtering logic): The filtering logic itself should be implemented using Angular's reactive programming capabilities (e.g., RxJS Observables) and TypeScript, not third-party filtering libraries.
Expected Behavior:
- When the component loads, all products should be displayed.
- Selecting a category should immediately update the product list to show only products from that category.
- Adjusting the price range should filter the list accordingly.
- Toggling the "In Stock" filter should show or hide out-of-stock items.
- Applying multiple filters simultaneously should result in a list of products that satisfy all conditions.
- Clicking "Clear Filters" should revert the display to show all products.
Edge Cases to Consider:
- What happens if no products match the selected filters? The list should be empty, and ideally, a message should inform the user.
- How to handle initial loading of products while filters are being applied?
- What if a user selects multiple categories?
- How to ensure the price range filtering handles valid number inputs and potential errors?
Examples
Example 1: Initial Load
Input: A predefined list of products (e.g., 5-10 products with varying categories, prices, and stock status).
Output: All products from the predefined list are displayed.
Explanation: On component initialization, no filters are applied, so the complete dataset is rendered.
Example 2: Category and Price Filtering
Input:
- Predefined Products:
[ {"id": 1, "name": "Laptop Pro", "category": "Electronics", "price": 1200, "inStock": true}, {"id": 2, "name": "Mechanical Keyboard", "category": "Electronics", "price": 150, "inStock": true}, {"id": 3, "name": "Gaming Mouse", "category": "Electronics", "price": 75, "inStock": false}, {"id": 4, "name": "T-Shirt", "category": "Apparel", "price": 25, "inStock": true}, {"id": 5, "name": "Jeans", "category": "Apparel", "price": 60, "inStock": true} ] - User Actions:
- Selects "Electronics" from the category filter.
- Sets the price range from $100 to $1500.
Output:
[
{"id": 1, "name": "Laptop Pro", "category": "Electronics", "price": 1200, "inStock": true},
{"id": 2, "name": "Mechanical Keyboard", "category": "Electronics", "price": 150, "inStock": true}
]
Explanation: The list is filtered to include only products in the "Electronics" category. Among those, only products with prices between $100 and $1500 (inclusive) are displayed. The "Gaming Mouse" is excluded because it's out of stock, and the "Mechanical Keyboard" and "Laptop Pro" are included because they meet both criteria.
Example 3: Availability and Price Filtering (Edge Case: No Results)
Input:
- Predefined Products: (Same as Example 2)
- User Actions:
- Checks the "In Stock Only" filter.
- Sets the price range from $0 to $50.
Output: An empty list, with a message like "No products found matching your criteria."
Explanation: After applying the filters, no products from the list are both in stock AND priced between $0 and $50. The "Gaming Mouse" is excluded due to being out of stock. The "T-Shirt" is in stock but costs $25, which is within the range. The "Jeans" are in stock but cost $60, outside the range. Therefore, only the T-Shirt should appear. Let's re-evaluate the example for no results.
Example 3 (Revised): Availability and Price Filtering (No Results Scenario)
Input:
- Predefined Products:
[ {"id": 1, "name": "Laptop Pro", "category": "Electronics", "price": 1200, "inStock": true}, {"id": 2, "name": "Mechanical Keyboard", "category": "Electronics", "price": 150, "inStock": true}, {"id": 3, "name": "Gaming Mouse", "category": "Electronics", "price": 75, "inStock": false}, {"id": 4, "name": "T-Shirt", "category": "Apparel", "price": 25, "inStock": true}, {"id": 5, "name": "Jeans", "category": "Apparel", "price": 60, "inStock": true} ] - User Actions:
- Checks the "In Stock Only" filter.
- Sets the price range from $500 to $800.
Output: An empty list, with a message like "No products found matching your criteria."
Explanation: The "In Stock Only" filter is applied. Then, the price range is set to $500-$800. None of the in-stock products ("Laptop Pro", "Mechanical Keyboard", "T-Shirt", "Jeans") fall within this specific price range, resulting in an empty filtered list.
Constraints
- The product list will contain a minimum of 10 products and a maximum of 100 products.
- Product prices will be between 1 and 5000 (inclusive).
- Product names, categories, and IDs will be unique.
- The filtering operation should update the UI within 200ms for typical user interactions on modern hardware.
- The solution should be implemented within a single Angular component.
Notes
- Consider using Angular's
OnPushchange detection strategy for performance optimization. - RxJS
combineLatestor similar operators can be very useful for managing multiple filter streams. - Think about how to structure your component's state to hold filter values and the filtered product list.
- You can simulate fetching products using a simple array or a service that returns an Observable of products.