How to embed a youtube video in an angular material dialog

By Adrian Matei

Youtube logo before bookmark title

It’s easy now to recognise the youtube video bookmarks on www.bookmarks.dev, by placing the youtube logo before the title
of the bookmark:

Bookmarks list with youtube logo

Also, when you click on the youtube logo, a dialog will pop where the video is embedded and you can play it directly there.
In this blog post I will show how it is implemented.

As a reminder, the www.bookmarks.dev website
uses Angular, with angular material and bootstrap for styling.

## The Bookmarks List Component

HTML Template

In the bookmarks list’s html template I check if the bookmark is a youtube video (a youtubeVideoId must be present), to display the youtube icon

...
  <h5 class="card-title">
    <i *ngIf="bookmark.youtubeVideoId" class="fab fa-youtube youtube-icon" (click)="playYoutubeVideo(bookmark)" title="Play youtube video"></i>
    <a href="" target="_blank" [innerHtml]="bookmark.name | highlight: queryText" (click)="onBookmarkLinkClick(bookmark)"></a>
    <sup class="external-link-hint"><i class="fas fa-external-link-alt"></i></sup>
  </h5>
...          

The Angular Bookmarks List Component – AsyncBookmarkListComponent

If the youtube icon is present, when clicked it triggers the method playYoutubeVideo int the AsyncBookmarkListComponent component:

  playYoutubeVideo(bookmark: Bookmark) {
    const dialogConfig = new MatDialogConfig();

    dialogConfig.disableClose = false;
    dialogConfig.autoFocus = true;

    let relativeWidth = (this.innerWidth * 80) / 100; // take up to 80% of the screen size
    if (this.innerWidth > 1500) {
      relativeWidth = (1500 * 80 ) / 100;
    } else {
      relativeWidth = (this.innerWidth * 80 ) / 100;
    }

    const relativeHeight = (relativeWidth * 9) / 16 + 120; // 16:9 to which we add 120 px for the dialog action buttons ("close")
    dialogConfig.width = relativeWidth + 'px';
    dialogConfig.height = relativeHeight + 'px';

    dialogConfig.data = {
      bookmark: bookmark
    };

    const dialogRef = this.deleteDialog.open(PlayYoutubeVideoDialogComponent, dialogConfig);
  }

The configuration of the dialog is quite strait forward. For smaller screens (width < 1500px), the dialog
will take up to 80% of the width and the height corresponds to a 16:9 ratio, to which you would add a 120px to properly display
the close button. For bigger screen we have fixed values which have the same ratio.

The window width (here innerWidth) is set in the ngOnInit() method of the component:

  ngOnInit(): void {
    this.innerWidth = window.innerWidth;
    ...
  }

Angular Material Dialog Integration

Let’s focus now on the angular material component that displays the youtube video.

HTML Template

The youtube video is embedded via an iframe.

<mat-dialog-content>
  <div class="videoWrapper">
    <iframe [src]='safeUrl' frameborder="0" allowfullscreen></iframe>
  </div>
</mat-dialog-content>

<hr>

<mat-dialog-actions class="app-dialog-actions">
  <button type="button" class="btn btn-primary btn-sm" (click)="close()">Close</button>
</mat-dialog-actions>

To systematically block XSS bugs, Angular treats all values as untrusted by default. So the iframe url needs to be marked as safe, to avoid being sanitized by Angular.

### Dialog Component – PlayYoutubeVideoDialogComponent

The iframe’s url (safeUrl) is marked as trusted by injecting the DomSanitizer and calling its bypassSecurityTrustResourceUrl method:

import { Component, Inject, OnInit } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
import { DomSanitizer } from '@angular/platform-browser';
import { Bookmark } from '../../core/model/bookmark';

@Component({
  selector: 'app-play-youtube-video-dialog',
  templateUrl: './play-youtube-video-dialog.component.html',
  styleUrls: ['./play-youtube-video-dialog.component.scss']
})
export class PlayYoutubeVideoDialogComponent implements OnInit {

  bookmark: Bookmark;
  safeUrl: any;

  constructor(
    private dialogRef: MatDialogRef<PlayYoutubeVideoDialogComponent>,
    @Inject(MAT_DIALOG_DATA) data,
    private _sanitizer: DomSanitizer
  ) {
    this.bookmark = data.bookmark;
    this.safeUrl = this._sanitizer.bypassSecurityTrustResourceUrl(`https://www.youtube.com/embed/${this.bookmark.youtubeVideoId}`);
  }

  ngOnInit() {
  }

  close() {
    this.dialogRef.close('Play Youtube Video Closed');
  }

}

CSS

To display the video in a “fluid” manner in the iframe, we use a solution pioneered by Thierry Koblentz
and presented on A List Apart in 2009: Creating Intrinsic Ratios for Video:

“The idea is to create a box with the proper ratio ( 16:9, etc.), then make the video inside that box stretch to fit the dimensions of the box. It’s that simple.”
I recommend you read the whole article to understand the details.

.videoWrapper {
  position: relative;
  padding-bottom: 56.25%; /* 16:9 */
  padding-top: 25px;
  height: 0;
}
.videoWrapper iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

Conclusion

Well it as simple as that. The whole code source for this for www.bookmarks.dev is available on Github.

I would really appreciate if you gave www.bookmarks.dev a try
and have a look at the generated public bookmarks at https://github.com/CodepediaOrg/bookmarks.

How to embed a youtube video in an angular material dialog was originally published by CodepediaOrg at CodepediaOrg on September 18, 2019.

Source:: codingpedia.org