Hone logo
Hone
Problems

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:

  1. Component Creation: Create an Angular component (e.g., ModalComponent) that serves as the overlay container.
  2. Content Projection: The ModalComponent should accept and display dynamic content passed into it. This can be achieved using Angular's content projection (<ng-content>).
  3. 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.
  4. Close Functionality: Clicking the close button should dismiss the modal.
  5. Styling: The overlay and modal should be visually distinct and properly positioned. Basic styling for accessibility (e.g., a semi-transparent background) is expected.
  6. Reusability: The ModalComponent should be designed to be reused with different content and configurations.

Expected Behavior:

  • When the ModalComponent is rendered and its isOpen property is true, 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">&times;</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">&times;</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 ModalComponent should 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 isOpen input property (boolean) to control its visibility.
  • The component should emit a closed event when the modal is dismissed.

Notes

  • Consider using position: fixed for the overlay to ensure it covers the entire viewport regardless of scrolling.
  • For the close button, you can use a simple text character like &times; 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 ModalComponent and likely a parent component to demonstrate its usage.
Loading editor...
typescript