Hone logo
Hone
Problems

Implementing a Custom ngFor Directive in Angular

This challenge asks you to build a simplified version of Angular's ngFor directive. Understanding how ngFor works under the hood is a valuable exercise in Angular internals and demonstrates how directives manipulate the DOM. Successfully completing this challenge will solidify your understanding of directive lifecycle hooks and template rendering.

Problem Description

You need to create a custom Angular directive called CustomFor that iterates over an array and renders a template for each item in the array. The directive should be usable in Angular templates similar to the built-in ngFor. The directive will receive an array as input and a template to repeat. It should dynamically create DOM elements based on the array's contents.

Key Requirements:

  • Input Array: The directive must accept an array as input, which will be the data to iterate over. This input should be named data.
  • Template: The directive must accept a template to be repeated for each item in the array. This template will be provided as a TemplateRef.
  • Index: The directive should provide an index variable within the template, representing the current iteration's index (starting from 0).
  • Dynamic Element Creation: The directive should dynamically create DOM elements based on the provided template and data.
  • ViewContainerRef: Use ViewContainerRef to add the rendered templates to the DOM.
  • No External Libraries: The solution should only use Angular's built-in features.

Expected Behavior:

When the CustomFor directive is used in a template, it should:

  1. Receive the data array and template as inputs.
  2. Iterate over the data array.
  3. For each item in the array, create a view instance using the template and ViewContainerRef.
  4. Pass the current item and its index to the view context.
  5. Append the created view to the DOM.

Edge Cases to Consider:

  • Empty Array: If the input array is empty, the directive should not render any elements.
  • Null or Undefined Array: Handle cases where the input array is null or undefined gracefully (e.g., by not rendering anything).
  • TemplateRef is Null/Undefined: Handle cases where the TemplateRef is null or undefined.

Examples

Example 1:

Input:
data = [1, 2, 3]
template:  <span>Item: {{ item }}, Index: {{ index }}</span>

Output:
<span>Item: 1, Index: 0</span>
<span>Item: 2, Index: 1</span>
<span>Item: 3, Index: 2</span>

Explanation: The directive iterates over the array [1, 2, 3]. For each number, it creates a span element with the provided template, substituting the `item` and `index` variables.

Example 2:

Input:
data = ['apple', 'banana', 'cherry']
template: <div class="fruit">{{ item }} - {{ index }}</div>

Output:
<div class="fruit">apple - 0</div>
<div class="fruit">banana - 1</div>
<div class="fruit">cherry - 2</div>

Explanation: The directive iterates over the array ['apple', 'banana', 'cherry']. For each fruit, it creates a div element with the provided template, substituting the `item` and `index` variables.

Example 3: (Edge Case - Empty Array)

Input:
data = []
template: <span>Item: {{ item }}, Index: {{ index }}</span>

Output:
(No output - no elements rendered)

Explanation: The directive receives an empty array.  Since there are no items to iterate over, no elements are rendered.

Constraints

  • Directive Structure: The directive must be a standard Angular directive (using @Directive).
  • Input Types: The data input must be of type Array<any>.
  • Performance: While not a primary focus, avoid unnecessary DOM manipulations. The solution should be reasonably performant for arrays of up to 100 elements.
  • Angular Version: Assume Angular version 14 or higher.

Notes

  • You'll need to use Angular's dependency injection to access ViewContainerRef and TemplateRef.
  • The ngFor directive uses TrackByFn for change detection optimization. For simplicity, this challenge does not require implementing TrackByFn.
  • Focus on the core logic of iterating over the array and rendering the template. Styling and complex template logic are outside the scope of this challenge.
  • Consider using *ngIf within the template to conditionally render elements based on the index if needed.
Loading editor...
typescript