Hone logo
Hone
Problems

Angular Portal System: Dynamic Content Display

This challenge focuses on building a basic portal system in Angular. Portals allow you to render a component's template in a different part of the DOM tree than where the component is defined, improving application structure and enabling features like modals, tooltips, and chat windows that appear "on top" of the main content. You'll create a simple portal that dynamically renders a provided component within a designated target location.

Problem Description

You are tasked with creating a reusable Angular component called Portal. This component will accept a component to be rendered as input and render it within a specified DOM element. The Portal component should:

  1. Accept a Component as Input: The Portal component should accept a component instance (e.g., a modal component, a tooltip component) as an input property named content. This component will be the content to be displayed within the portal.
  2. Accept a Target Element Selector as Input: The Portal component should accept a string input property named target which represents a CSS selector that identifies the DOM element where the content should be rendered.
  3. Dynamically Render the Component: Upon initialization, the Portal component should find the DOM element matching the provided target selector. It should then dynamically create an Angular component instance from the content input and append its template to the target element.
  4. Handle Component Destruction: When the Portal component is destroyed, it should destroy the dynamically created component instance to prevent memory leaks.
  5. Error Handling: If the target element is not found, the portal should log an error to the console and not attempt to render the content.

Expected Behavior:

  • When the Portal component is initialized, it should attempt to find the element specified by the target selector.
  • If the element is found, it should create an instance of the component passed as content and append its template to the target element.
  • When the Portal component is destroyed, the dynamically created component should be destroyed.
  • If the target element is not found, an error message should be logged to the console.

Examples

Example 1:

Input:
Portal Component:
  - content: MyComponent (a simple component displaying "Hello from MyComponent!")
  - target: '#portal-target'

HTML:
<div id="portal-target"></div>

Output:
The text "Hello from MyComponent!" is rendered inside the <div id="portal-target"> element.
Explanation: The Portal component finds the element with id 'portal-target' and renders the template of MyComponent within it.

Example 2:

Input:
Portal Component:
  - content: AnotherComponent (a component displaying a button)
  - target: '.my-portal'

HTML:
<div class="my-portal"></div>

Output:
The button from AnotherComponent is rendered inside the <div class="my-portal"> element.
Explanation: The Portal component finds the element with class 'my-portal' and renders the template of AnotherComponent within it.

Example 3: (Edge Case)

Input:
Portal Component:
  - content: SomeComponent
  - target: '#non-existent-element'

HTML:
(No element with id 'non-existent-element' exists in the DOM)

Output:
An error message is logged to the console: "Target element not found for selector: #non-existent-element".
The component is not rendered anywhere.
Explanation: The Portal component fails to find the target element and does not attempt to render the content.

Constraints

  • The target selector must be a valid CSS selector string.
  • The content input must be a valid Angular component class.
  • The dynamically created component should be destroyed when the Portal component is destroyed.
  • The solution should be implemented using Angular's ComponentFactoryResolver and ViewContainerRef.
  • Performance: The component creation and destruction should be efficient and not introduce noticeable delays.

Notes

  • Consider using ViewContainerRef.clear() to remove any existing content from the target element before rendering the new component.
  • You'll need to inject ComponentFactoryResolver and ViewContainerRef into your Portal component.
  • Think about how to handle cases where the target element might be dynamically added to the DOM after the Portal component has been initialized. While not required for this basic implementation, it's a good consideration for a more robust portal system.
  • Focus on the core functionality of dynamically rendering a component within a specified target element. Styling and advanced features are not required for this challenge.
Loading editor...
typescript