Skip to main content

Overview

The DialogService is a shared Angular service that manages Material Design dialogs for displaying media item details and trailers. It uses lazy loading to dynamically import dialog components on demand, improving initial load performance.

Import

import { DialogService } from 'src/app/shared/services/dialog/dialog.service';
import { MediaItem } from 'src/app/shared/models/movie.model';

Dependencies

The service depends on:
  • MatDialog from @angular/material/dialog
  • OmdbService for fetching detailed media information
  • ToastrService from ngx-toastr for error notifications

Methods

openMediaItem

Opens a Material dialog displaying detailed information about a media item (movie, series, or game). The dialog is lazily loaded and its size adapts to the window dimensions.
openMediaItem(
  windowWidth: number,
  mediaItem: MediaItem,
  fromFavoritesSection: boolean
): Observable<void>
windowWidth
number
required
The current window width in pixels, used to calculate optimal dialog dimensions
mediaItem
MediaItem
required
The media item to display. Must include at minimum the imdbID property
fromFavoritesSection
boolean
required
Indicates whether the dialog was opened from the favorites page (enables edit/delete actions)
return
Observable<void>
An Observable that completes when the dialog operation finishes. Errors are handled internally with toast notifications.
Dialog Sizing: The dialog automatically adjusts its dimensions based on window width:
  • Mobile (<600px): 90% height, 80% width
  • Tablet (600-800px): 85% height, 70% width
  • Desktop (>800px): 85% height, 85% width
Example:
navbar.component.ts
import { DialogService } from 'src/app/shared/services/dialog/dialog.service';
import { MediaItem } from 'src/app/shared/models/movie.model';

export class NavbarComponent {
  constructor(private dialogService: DialogService) {}

  openMovieDetails(movie: MediaItem) {
    const windowWidth = window.innerWidth;
    
    this.dialogService.openMediaItem(windowWidth, movie, false)
      .subscribe({
        next: () => console.log('Dialog opened successfully'),
        error: (err) => console.error('Failed to open dialog:', err)
      });
  }
}
Workflow:
1

Fetch Details

Calls OmdbService.getMediaItemInfo() to retrieve complete media details from OMDB API
2

Lazy Load Component

Dynamically imports MediaItemDialogComponent using dynamic import() for code splitting
3

Open Dialog

Opens the Material dialog with the fetched data and responsive dimensions
4

Error Handling

Shows toast notification if API call fails or component import fails

openTrailerDialog

Opens a Material dialog for playing a video trailer from a URL (typically YouTube). The component is lazily loaded on demand.
openTrailerDialog(videoUrl: string): void
videoUrl
string
required
The URL of the video to play. Typically a YouTube URL that will be sanitized and embedded in an iframe
Dialog Configuration:
  • Width: 80% of viewport width (max 1200px)
  • Height: 70% of viewport height (max 800px)
  • Auto-focus disabled for better UX
  • User can close by clicking outside or pressing ESC
Example:
movie-dialog.component.ts
import { DialogService } from 'src/app/shared/services/dialog/dialog.service';

export class MediaItemDialogComponent {
  constructor(private dialogService: DialogService) {}

  playTrailer(trailerUrl: string) {
    this.dialogService.openTrailerDialog(trailerUrl);
  }
}
Error Handling:
// If the TrailerDialogComponent fails to load, a toast error is displayed:
// "Could not load trailer dialog"

Implementation Details

Lazy Loading Pattern

Both dialog methods use dynamic import() to lazy load their components:
// Lazy loading with error handling
import('../../components/movie-dialog/movie-dialog.component')
  .then((module) => {
    this.dialog.open(module.MediaItemDialogComponent, config);
  })
  .catch((error) => {
    console.error('Failed to load component:', error);
    this.toastrService.error('Could not load dialog');
  });
This pattern:
  • Reduces initial bundle size
  • Loads dialog code only when needed
  • Improves application startup time

RxJS Integration

openMediaItem() returns an Observable that chains:
  1. API call to fetch media details
  2. Component import
  3. Dialog opening
return this.OmdbService.getMediaItemInfo(mediaItem.imdbID).pipe(
  switchMap((response) => from(import('...'))),
  tap({ /* open dialog */ }),
  map(() => undefined)
);

MediaItem Model

The data model passed to dialog methods

OmdbService

Service that fetches detailed media information

Movie Dialog Component

The lazily-loaded dialog component for media details

Trailer Dialog Component

The lazily-loaded dialog component for video playback

Usage in Components

DialogService is typically injected into components that need to display media details:
// In navbar, search results, or favorites components
constructor(private dialogService: DialogService) {}

onMediaItemClick(item: MediaItem) {
  this.dialogService.openMediaItem(
    window.innerWidth,
    item,
    this.isOnFavoritesPage
  ).subscribe();
}
Always subscribe to the Observable returned by openMediaItem(), even if you don’t need the result. This ensures the dialog operation executes.
The service handles all error cases internally with toast notifications, so components don’t need to implement additional error handling.

Build docs developers (and LLMs) love