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:
- Accept a Component as Input: The
Portalcomponent should accept a component instance (e.g., a modal component, a tooltip component) as an input property namedcontent. This component will be the content to be displayed within the portal. - Accept a Target Element Selector as Input: The
Portalcomponent should accept a string input property namedtargetwhich represents a CSS selector that identifies the DOM element where the content should be rendered. - Dynamically Render the Component: Upon initialization, the
Portalcomponent should find the DOM element matching the providedtargetselector. It should then dynamically create an Angular component instance from thecontentinput and append its template to the target element. - Handle Component Destruction: When the
Portalcomponent is destroyed, it should destroy the dynamically created component instance to prevent memory leaks. - 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
Portalcomponent is initialized, it should attempt to find the element specified by thetargetselector. - If the element is found, it should create an instance of the component passed as
contentand append its template to the target element. - When the
Portalcomponent 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
targetselector must be a valid CSS selector string. - The
contentinput must be a valid Angular component class. - The dynamically created component should be destroyed when the
Portalcomponent is destroyed. - The solution should be implemented using Angular's
ComponentFactoryResolverandViewContainerRef. - 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
ComponentFactoryResolverandViewContainerRefinto yourPortalcomponent. - Think about how to handle cases where the target element might be dynamically added to the DOM after the
Portalcomponent 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.