Mastering Angular Control Flow: Conditional Rendering and Iteration
This challenge focuses on implementing Angular's powerful control flow syntax, specifically *ngIf for conditional rendering and *ngFor for iterating over lists. Mastering these directives is fundamental for building dynamic and responsive user interfaces in Angular applications, allowing you to show or hide elements based on data and to display collections of items efficiently.
Problem Description
You are tasked with creating an Angular component that dynamically displays information about a list of products. The component should demonstrate the use of *ngIf to conditionally show a "Featured Product" section and *ngFor to render a list of all products.
Key Requirements:
-
Conditional Featured Product Display:
- Implement a property in your component that holds a single
Productobject (ornull). - Use
*ngIfin the template to render a specific HTML structure (e.g., adivwith a heading "Featured Product") only when this featured product property is notnull. - Inside the
*ngIfblock, display the name and price of the featured product.
- Implement a property in your component that holds a single
-
Product List Rendering:
- Implement a property in your component that holds an array of
Productobjects. - Use
*ngForin the template to iterate over this array. - For each product in the array, render a list item (
<li>) displaying the product's name, price, and a unique identifier (e.g.,id). - Ensure you use the
trackByoption with*ngForfor better performance when the list might change.
- Implement a property in your component that holds an array of
-
Component Structure:
- Create a new Angular component (e.g.,
ProductListComponent). - Define an interface for the
Productobject with properties likeid,name, andprice.
- Create a new Angular component (e.g.,
Expected Behavior:
- When a featured product is assigned, the "Featured Product" section should appear, displaying its details.
- When no featured product is assigned (i.e., the property is
null), the "Featured Product" section should not be rendered. - The list of all products should be rendered correctly, with each product displayed as a list item.
Edge Cases to Consider:
- What happens if the product list is empty?
- How should the
trackByfunction handle potential changes to the product list?
Examples
Example 1: With Featured Product and Products
// In your component.ts file:
interface Product {
id: number;
name: string;
price: number;
}
export class ProductListComponent {
featuredProduct: Product | null = { id: 101, name: 'Wireless Mouse', price: 25.99 };
products: Product[] = [
{ id: 1, name: 'Mechanical Keyboard', price: 75.00 },
{ id: 2, name: 'Gaming Monitor', price: 299.99 },
{ id: 3, name: 'Webcam 1080p', price: 49.50 },
];
trackByProductId(index: number, product: Product): number {
return product.id;
}
}
<!-- In your component.html file: -->
<div *ngIf="featuredProduct">
<h2>Featured Product</h2>
<p>Name: {{ featuredProduct.name }}</p>
<p>Price: ${{ featuredProduct.price }}</p>
</div>
<h3>All Products</h3>
<ul>
<li *ngFor="let product of products; trackBy: trackByProductId">
{{ product.id }} - {{ product.name }} - ${{ product.price }}
</li>
</ul>
Output (rendered HTML):
<div>
<h2>Featured Product</h2>
<p>Name: Wireless Mouse</p>
<p>Price: $25.99</p>
</div>
<h3>All Products</h3>
<ul>
<li>1 - Mechanical Keyboard - $75.00</li>
<li>2 - Gaming Monitor - $299.99</li>
<li>3 - Webcam 1080p - $49.50</li>
</ul>
Explanation:
The featuredProduct is not null, so the div containing "Featured Product" details is rendered. The products array is iterated, and each product is displayed as a list item.
Example 2: Without Featured Product, with Products
// In your component.ts file:
interface Product {
id: number;
name: string;
price: number;
}
export class ProductListComponent {
featuredProduct: Product | null = null; // Featured product is null
products: Product[] = [
{ id: 1, name: 'Mechanical Keyboard', price: 75.00 },
{ id: 2, name: 'Gaming Monitor', price: 299.99 },
];
trackByProductId(index: number, product: Product): number {
return product.id;
}
}
<!-- In your component.html file: -->
<div *ngIf="featuredProduct">
<h2>Featured Product</h2>
<p>Name: {{ featuredProduct.name }}</p>
<p>Price: ${{ featuredProduct.price }}</p>
</div>
<h3>All Products</h3>
<ul>
<li *ngFor="let product of products; trackBy: trackByProductId">
{{ product.id }} - {{ product.name }} - ${{ product.price }}
</li>
</ul>
Output (rendered HTML):
<h3>All Products</h3>
<ul>
<li>1 - Mechanical Keyboard - $75.00</li>
<li>2 - Gaming Monitor - $299.99</li>
</ul>
Explanation:
Since featuredProduct is null, the *ngIf condition is false, and the "Featured Product" div is not rendered. The product list is still rendered correctly.
Example 3: Empty Product List
// In your component.ts file:
interface Product {
id: number;
name: string;
price: number;
}
export class ProductListComponent {
featuredProduct: Product | null = { id: 101, name: 'Wireless Mouse', price: 25.99 };
products: Product[] = []; // Empty product list
trackByProductId(index: number, product: Product): number {
return product.id;
}
}
<!-- In your component.html file: -->
<div *ngIf="featuredProduct">
<h2>Featured Product</h2>
<p>Name: {{ featuredProduct.name }}</p>
<p>Price: ${{ featuredProduct.price }}</p>
</div>
<h3>All Products</h3>
<ul>
<li *ngFor="let product of products; trackBy: trackByProductId">
{{ product.id }} - {{ product.name }} - ${{ product.price }}
</li>
</ul>
Output (rendered HTML):
<div>
<h2>Featured Product</h2>
<p>Name: Wireless Mouse</p>
<p>Price: $25.99</p>
</div>
<h3>All Products</h3>
<ul>
<!-- Empty ul, no li elements -->
</ul>
Explanation:
The featured product is displayed. The products array is empty, so *ngFor iterates zero times, resulting in an empty <ul> element.
Constraints
- Your Angular component must be written in TypeScript.
- You should use the standard Angular template syntax for control flow.
- The
trackByfunction should correctly return theidof the product. - The component should be standalone or part of a basic Angular application structure.
Notes
- Remember to define the
Productinterface. - The
trackByfunction is crucial for performance, especially when dealing with large or frequently updated lists. It helps Angular efficiently update the DOM by identifying which items have changed, been added, or removed. - Consider how you would pass data into this component if it were a reusable piece of your application (e.g., using
@Input()properties). While not required for this specific challenge, it's a good practice to think about.