DEV Community

loading...
Cover image for How to play a youtube video in an angular material dialog

How to play a youtube video in an angular material dialog

Adrian Matei
Making bookmarking easier for devs with www.codever.land
Originally published at codepedia.org Updated on ・3 min read

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:
Bookmark 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="{{bookmark.location}}" 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>
...          
Enter fullscreen mode Exit fullscreen mode

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);
  }
Enter fullscreen mode Exit fullscreen mode

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;
    ...
  }
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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');
  }

}
Enter fullscreen mode Exit fullscreen mode

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%;
}
Enter fullscreen mode Exit fullscreen mode

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.

This post was originally posted at How to embed a youtube video in an angular material dialog

Discussion (0)