Hone logo
Hone
Problems

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:

  1. Conditional Featured Product Display:

    • Implement a property in your component that holds a single Product object (or null).
    • Use *ngIf in the template to render a specific HTML structure (e.g., a div with a heading "Featured Product") only when this featured product property is not null.
    • Inside the *ngIf block, display the name and price of the featured product.
  2. Product List Rendering:

    • Implement a property in your component that holds an array of Product objects.
    • Use *ngFor in 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 trackBy option with *ngFor for better performance when the list might change.
  3. Component Structure:

    • Create a new Angular component (e.g., ProductListComponent).
    • Define an interface for the Product object with properties like id, name, and price.

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 trackBy function 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 trackBy function should correctly return the id of the product.
  • The component should be standalone or part of a basic Angular application structure.

Notes

  • Remember to define the Product interface.
  • The trackBy function 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.
Loading editor...
typescript