Angular Overlay Component: Building a Modal Dialog
This challenge requires you to implement a reusable modal dialog component in Angular. Modals are a common UI pattern for displaying important information or prompting user interaction without navigating away from the current page. You will leverage Angular's component architecture and styling to create a flexible and accessible overlay.
Problem Description
Your task is to create an Angular component that acts as a generic overlay, capable of displaying arbitrary content within a modal dialog. This component should be easily integrated into existing Angular applications.
Key Requirements:
- Component Creation: Create an Angular component (e.g.,
ModalComponent) that serves as the overlay container. - Content Projection: The
ModalComponentshould accept and display dynamic content passed into it. This can be achieved using Angular's content projection (<ng-content>). - Modal Structure: The modal should consist of:
- A background overlay that covers the entire viewport.
- A central modal dialog box.
- A close button (e.g., an 'X' icon) within the modal header.
- Close Functionality: Clicking the close button should dismiss the modal.
- Styling: The overlay and modal should be visually distinct and properly positioned. Basic styling for accessibility (e.g., a semi-transparent background) is expected.
- Reusability: The
ModalComponentshould be designed to be reused with different content and configurations.
Expected Behavior:
- When the
ModalComponentis rendered and itsisOpenproperty istrue, the overlay and modal should appear on the screen. - Content provided via content projection should be rendered inside the modal's body.
- Clicking the close button should trigger an event to signal the modal should be closed.
- Clicking outside the modal dialog (on the overlay) should also dismiss the modal.
Edge Cases:
- Consider how to handle modals with very long content that might exceed the viewport height.
- Ensure the modal is responsive and adapts to different screen sizes.
Examples
Example 1: Basic Modal
// parent.component.html
<app-modal [isOpen]="isModalOpen" (closed)="isModalOpen = false">
<div class="modal-header">
<h2>My Awesome Modal</h2>
<button class="close-button">×</button>
</div>
<div class="modal-body">
<p>This is the content of the modal. You can put any HTML here!</p>
<button (click)="isModalOpen = false">Okay</button>
</div>
</app-modal>
<button (click)="isModalOpen = true">Open Modal</button>
// parent.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.scss']
})
export class ParentComponent {
isModalOpen = false;
}
Output:
When "Open Modal" is clicked: A modal dialog appears. The header contains "My Awesome Modal" and a close button. The body contains the paragraph text and an "Okay" button. The background is a semi-transparent overlay. Clicking the "Okay" button or the close button dismisses the modal.
Example 2: Nested Content Projection
Imagine a more complex scenario where the modal's content itself has interactive elements.
// parent.component.html
<app-modal [isOpen]="isFormModalOpen" (closed)="isFormModalOpen = false">
<div class="modal-header">
<h2>User Registration</h2>
<button class="close-button">×</button>
</div>
<div class="modal-body">
<form>
<label for="name">Name:</label>
<input type="text" id="name" name="name"><br><br>
<label for="email">Email:</label>
<input type="email" id="email" name="email"><br><br>
<button type="submit">Submit</button>
</form>
</div>
</app-modal>
<button (click)="isFormModalOpen = true">Open Registration Form</button>
// parent.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.scss']
})
export class ParentComponent {
isFormModalOpen = false;
}
Output:
When "Open Registration Form" is clicked: A modal appears with a "User Registration" header and a form for name and email. The user can interact with the form fields and click the "Submit" button. Clicking the close button dismisses the modal.
Constraints
- The
ModalComponentshould be implemented using Angular CLI and TypeScript. - Styling should be managed within the component's SCSS file or a global stylesheet, ensuring a clean separation of concerns.
- Avoid using external libraries for the core modal functionality. You can use Angular's built-in animations for a smoother appearance/disappearance if desired.
- The component should have an
isOpeninput property (boolean) to control its visibility. - The component should emit a
closedevent when the modal is dismissed.
Notes
- Consider using
position: fixedfor the overlay to ensure it covers the entire viewport regardless of scrolling. - For the close button, you can use a simple text character like
×or an SVG icon. - Think about how to manage focus within the modal and return focus to the element that triggered the modal when it closes. This is crucial for accessibility.
- The "click outside to close" functionality can be implemented by attaching a click listener to the overlay element.
- You'll need to create the
ModalComponentand likely a parent component to demonstrate its usage.