Hone logo
Hone
Problems

Angular Dynamic Template Parser

In modern web development, it's common to need to render dynamic content based on user-defined templates or configurations. This challenge focuses on building a robust template parser within an Angular application, allowing for the rendering of dynamic content with embedded variables and basic control structures. This is crucial for scenarios like email generation, dynamic form builders, or personalized user interfaces.

Problem Description

Your task is to create an Angular component that can parse and render a given string template. This template can contain plain text, placeholders for dynamic data, and simple conditional logic.

Key Requirements:

  1. Placeholder Replacement: The parser should replace placeholders enclosed in double curly braces {{ }} with corresponding values from a provided data context.
  2. Basic Conditional Logic: Support for a simple if directive. The syntax for an if block will be {{ #if variableName }} ... {{ /if }}. The content within the if block should only be rendered if the variableName exists and its value is truthy in the provided data context.
  3. Data Context: The component should accept a data object (context) that provides the values for placeholders and conditional checks.
  4. Component Implementation: The solution should be implemented as a reusable Angular component.

Expected Behavior:

  • When the component receives a template string and a data context, it should render the template to the DOM.
  • Placeholders should be dynamically replaced.
  • if blocks should conditionally render their content.
  • If a placeholder or conditional variable is not found in the data context, it should be treated as an empty string for replacement and false for conditional checks.

Edge Cases to Consider:

  • Empty template string.
  • Template string with no placeholders or directives.
  • Nested if statements (optional, but good to consider for future expansion).
  • Data context with missing properties.
  • Data context properties with falsy values (e.g., 0, false, null, undefined, "").
  • Special characters within the template that are not part of placeholders or directives.

Examples

Example 1: Simple Placeholder Replacement

Input Template: "Hello, {{ name }}! You have {{ unreadCount }} new messages."
Input Data Context: { name: "Alice", unreadCount: 5 }
Output: "Hello, Alice! You have 5 new messages."

Explanation: {{ name }} is replaced with "Alice" and {{ unreadCount }} is replaced with 5 from the data context.

Example 2: Conditional Rendering

Input Template: "Welcome back, {{ user.firstName }}! {{ #if isAdmin }} You have administrative privileges. {{ /if }}"
Input Data Context: { user: { firstName: "Bob" }, isAdmin: true }
Output: "Welcome back, Bob! You have administrative privileges."

Explanation: {{ user.firstName }} is replaced with "Bob". The {{ #if isAdmin }} block is rendered because isAdmin is true in the context.

Example 3: Conditional Rendering (False)

Input Template: "Your order status is: {{ orderStatus }}. {{ #if shipped }} Your order has been shipped. {{ /if }}"
Input Data Context: { orderStatus: "Processing", shipped: false }
Output: "Your order status is: Processing."

Explanation: {{ orderStatus }} is replaced with "Processing". The {{ #if shipped }} block is not rendered because shipped is false in the context.

Example 4: Missing Data

Input Template: "User: {{ user.name }}, Email: {{ user.email }}"
Input Data Context: { user: { name: "Charlie" } }
Output: "User: Charlie, Email: "

Explanation: {{ user.name }} is replaced with "Charlie". {{ user.email }} is not found in the context, so it's replaced with an empty string.

Example 5: Nested Access and Falsy Value

Input Template: "User Profile: {{ user.profile.id }}. Status: {{ #if user.active }} Active {{ else }} Inactive {{ /if }}"
Input Data Context: { user: { profile: { id: 123 }, active: 0 } }
Output: "User Profile: 123. Status:  Inactive "

Explanation: {{ user.profile.id }} is replaced with 123. The {{ #if user.active }} condition checks user.active which is 0. 0 is falsy, so the else block content is rendered. (Note: else is an extension not explicitly required, but this example demonstrates how falsy values are handled in the if check). If else is not supported, the output would be: "User Profile: 123. Status: ".

Constraints

  • The template string can be up to 5000 characters long.
  • The data context will be a plain JavaScript object.
  • The parser should handle arbitrarily nested properties within the data context (e.g., user.profile.address.city).
  • The parsing and rendering should complete within 50ms for typical template sizes and data contexts to ensure a smooth user experience.
  • Only double curly braces {{ }} are used for placeholders and directives.
  • Directives are limited to {{ #if variable }} and {{ /if }}. An optional {{ else }} directive can also be considered.

Notes

  • Consider how you will handle escaping of characters within the template. For this challenge, assume standard HTML rendering.
  • Think about how to safely access nested properties from the data context to avoid errors when properties are missing.
  • The solution should be implemented using Angular's component lifecycle and template rendering capabilities. You might consider using DomSanitizer if directly manipulating innerHTML, but a more Angular-native approach is preferred.
  • The core logic can be implemented in a service or directly within the component.
  • Focus on correctness and robustness first, then optimize for performance.
Loading editor...
typescript