Skip to content

How to add a YouTube Video Player

YouTube is, without any doubt, one of the most popular websites for video-sharing today. It’s really easy to upload any video format and share it with your friends. Also, the YouTube team provides an API Reference to let you embed a YouTube video on any website and, of course, control it using JavaScript.

Some time ago, I started working on a web application using the Angular framework, and one of the main features involved the use of an embedded YouTube video player to avoid the user’s context switching, or opening a separate browser to see a video. At that time, there was no native solution to solve this problem like there is today.

In this MediaJam we’ll leverage a TypeScript-oriented solution, using the latest Angular version, to build a small web application, and embed a YouTube video player. One of the standout features of the Angular YouTube Player is its ease of use, ensuring a straightforward integration process for developers.

You’ll need to have installed the following tools in your local environment:

  • The latest LTS version of Node.js available is recommended.
  • Either NPM or Yarn as a package manager.
  • The Angular CLI tool (Command-line interface for Angular).

Let’s create a small project from scratch using the Angular CLI tool.

First, you can create the folder using mkdir angular-youtube-player-demo.

Then, enter the newly created folder, and run the ng new tool following the below syntax:

ng new <project-name> [options]
Code language: HTML, XML (xml)

The ng new command will take the project-name as an input to have an application ready following best practices. In this case, let’s use the directory we just created above.

cd angular-youtube-player-demo
ng new angular-youtube-player-demo --directory ./ --routing --prefix corp --style css --minimal
Code language: JavaScript (javascript)

This command will initialize a base project, using some configuration options:

  • angular-youtube-player-demo. Sets the name of the Angular project.
  • --directory ./. Sets the directory to generate the files.
  • --routing. Creates a routing module.
  • --prefix corp. Defines a prefix to be applied to the selectors for created components(corp in this case). The default value is app.
  • --style css. The file extension for the styling files.
  • --minimal. Creates the project without any testing framework. Useful when you’re working on a proof-of-concept project, for example.

The output of the previous command will be as follows.

CREATE README.md (1033 bytes)
CREATE .gitignore (631 bytes)
CREATE angular.json (3163 bytes)
CREATE package.json (775 bytes)
CREATE tsconfig.json (538 bytes)
CREATE .browserslistrc (703 bytes)
CREATE tsconfig.app.json (287 bytes)
CREATE src/favicon.ico (948 bytes)
CREATE src/index.html (312 bytes)
CREATE src/main.ts (372 bytes)
CREATE src/polyfills.ts (2830 bytes)
CREATE src/styles.css (80 bytes)
CREATE src/assets/.gitkeep (0 bytes)
CREATE src/environments/environment.prod.ts (51 bytes)
CREATE src/environments/environment.ts (662 bytes)
CREATE src/app/app-routing.module.ts (245 bytes)
CREATE src/app/app.module.ts (393 bytes)
CREATE src/app/app.component.ts (1503 bytes)
✔ Packages installed successfully.

If you pay attention to the generated files and directories, you’ll see a minimal project structure for the source code too:

|- src/
    |- app/
        |- app.module.ts
        |- app-routing.module.ts
        |- app.component.ts

Before embedding any video in our application, install the @angular/youtube-player package.

npm install --save @angular/youtube-player
Code language: CSS (css)

If you use Yarn, instead run

yarn add @angular/youtube-player
Code language: CSS (css)

Open the app.module.ts file and import the YouTubePlayerModule

// ... other imports
import {YouTubePlayerModule} from '@angular/youtube-player';

@NgModule({
  declarations: [
    //...
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    YouTubePlayerModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
Code language: JavaScript (javascript)

This can be done in a separate module if that’s the case in your implementation.

It’s worth noting that the Angular YouTube Player doesn’t just make embedding videos simpler; it also brings a plethora of customization options. Whether it’s adjusting the player’s appearance, tweaking its controls, or changing its size, the component provides the tools for fine-grained control over how the player behaves and looks.

Let’s define the data model by creating a new file in app/model folder. We can use the Angular CLI tool for that:

ng generate interface model/video
CREATE src/app/model/video.ts (28 bytes)

Then, open the brand new file video.ts in your editor, and set the model using a TypeScript interface.

export interface Video {
    title: string;
    link: string;
}
Code language: CSS (css)

Let’s create the video-player component, again, using the Angular CLI tool:

ng generate component video-player
CREATE src/app/video-player/video-player.component.ts (283 bytes)
UPDATE src/app/app.module.ts (497 bytes)

Now, open the video-player.component.ts file, and add the following TypeScript code:

export class VideoPlayerComponent implements OnInit {
  private apiLoaded = false;

  @Input() videoId: string;

  constructor() { }

  ngOnInit(): void {
    if(!this.apiLoaded) {
      const tag = document.createElement('script');
      tag.src = 'https://www.youtube.com/iframe_api';
      document.body.appendChild(tag);
      this.apiLoaded = true;
    }
  }
}
Code language: JavaScript (javascript)

The ngOnInit() function is part of the component lifecycle, and it will be called once the data property(videoId) has been initialized.

Since the @angular/youtube-player package defines a component wrapper based on the YouTube player API, it needs to load the IFrame Player asynchronously.

The method used in the previous code snippet access the DOM, and download the API code through the <script> tag. It would be something like this:

<script src="https://www.youtube.com/iframe_api"></script>
Code language: HTML, XML (xml)

Next, define the template along with the Property binding through videoId as follows.

<youtube-player [videoId]="videoId"></youtube-player>
Code language: HTML, XML (xml)

Let’s create a couple of video entries to be rendered through the Video Player Component we just created.

Open the app.component.ts file, and set a videoList attribute.

// ... other imports
import { Video } from './model/video';

export class AppComponent {
  videoList: Video[] = [
    {
      title: '[Debugging] Expression has changed after it was checked',
      link: 'https://www.youtube.com/watch?v=O47uUnJjbJc'
    },
    {
      title: '[Debugging] The pipe {name} could not be found',
      link: 'https://www.youtube.com/watch?v=maI2u6Sxk9M'
    }
  ];
}
Code language: JavaScript (javascript)

The videoList attribute contains a set of Video objects with the title and URL.

Next, let’s render a list of videos, and use the <corp-video-player> component. Open the app.component.ts file, and update the template section.

<div style="text-align:center">
  <h1>
    Angular YouTube Video Player Demo
  </h1>
</div>
<h2>Select a Video</h2>
<ul>
  <li *ngFor="let video of videoList">
    <h2><a href="#" (click)="selectVideo(video)">{{video.title}}</a></h2>
  </li>
</ul>
<corp-video-player [videoId]="currentVideoId"></corp-video-player>
Code language: HTML, XML (xml)

As you can see, there are two bindings here: An Event binding((click)="selectVideo(video)") and a Property Binding([videoId]="currentVideoId"). Let’s define both of them to have the final code in the app.component.ts file.

export class AppComponent {
  videoList: Video[] = [
    // Objects defined above
  ];

  currentVideoId: string;

  selectVideo(video: Video) {
    const params = new URL(video.link).searchParams;
    this.currentVideoId = params.get('v');
  }
}
Code language: JavaScript (javascript)

Pay attention to the selectVideo() function implementation, since it “extracts” the video identifier from a URL object. Then, the Id value is assigned to the currentVideoId property.

Every time the currentVideoId gets changed, the <corp-video-player> will be updated because of the Property binding.

Name Description
@Input() videoId: string The YouTube video identifier to be rendered
@Input() width: number The width of the video player
@Input() height: number The height of the video player
@Input() startSeconds: number The moment when the player is supposed to start playing
@Input() endSeconds: number The moment when the player is supposed to stop playing
@Input() suggestedQuality: YT.SuggestedVideoQuality The suggested quality of the player
@Input() playerVars: YT.PlayerVars Extra parameters used to configure the player. See here
@Input() showBeforeIframeApiLoads: boolean Whether the iFrame will attempt to load regardless of the status of the API on the page.
Name
@Output() ready: Observable<YT.PlayerEvent>
@Output() stateChange: Observable<YT.OnStateChangeEvent>
@Output() error: Observable<YT.OnErrorEvent>
@Output() apiChange: Observable<YT.PlayerEvent>
@Output() playbackQualityChange: Observable<YT.OnPlaybackQualityChangeEvent>
@Output() playbackRateChange: Observable<YT.OnPlaybackRateChangeEvent>

Learn more about the available properties and events here.

Find the source code available in GitHub.

If you prefer, you can play around with the project in CodeSandbox too:

Feel free to reach out on Twitter if you have any questions. Follow me on GitHub to see more about my work.

Back to top

Featured Post