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.
Prerequisites
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).
Initialize the Project
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:
1ng new <project-name> [options]
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.
1cd angular-youtube-player-demo2ng new angular-youtube-player-demo --directory ./ --routing --prefix corp --style css --minimal
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 isapp
.--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.
1CREATE README.md (1033 bytes)2CREATE .gitignore (631 bytes)3CREATE angular.json (3163 bytes)4CREATE package.json (775 bytes)5CREATE tsconfig.json (538 bytes)6CREATE .browserslistrc (703 bytes)7CREATE tsconfig.app.json (287 bytes)8CREATE src/favicon.ico (948 bytes)9CREATE src/index.html (312 bytes)10CREATE src/main.ts (372 bytes)11CREATE src/polyfills.ts (2830 bytes)12CREATE src/styles.css (80 bytes)13CREATE src/assets/.gitkeep (0 bytes)14CREATE src/environments/environment.prod.ts (51 bytes)15CREATE src/environments/environment.ts (662 bytes)16CREATE src/app/app-routing.module.ts (245 bytes)17CREATE src/app/app.module.ts (393 bytes)18CREATE src/app/app.component.ts (1503 bytes)19✔ 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:
1|- src/2 |- app/3 |- app.module.ts4 |- app-routing.module.ts5 |- app.component.ts
Video Player Implementation
Install the YouTube Player Package
Before embedding any video in our application, install the @angular/youtube-player
package.
1npm install --save @angular/youtube-player
If you use Yarn, instead run
1yarn add @angular/youtube-player
Import the YouTubePlayer Module
Open the app.module.ts
file and import the YouTubePlayerModule
1// ... other imports2import {YouTubePlayerModule} from '@angular/youtube-player';34@NgModule({5 declarations: [6 //...7 ],8 imports: [9 BrowserModule,10 AppRoutingModule,11 YouTubePlayerModule12 ],13 providers: [],14 bootstrap: [AppComponent]15})16export class AppModule { }
This can be done in a separate module if that's the case in your implementation.
Define the Data Model
Let's define the data model by creating a new file in app/model
folder. We can use the Angular CLI tool for that:
1ng generate interface model/video2CREATE 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.
1export interface Video {2 title: string;3 link: string;4}
Create the Video Player Component
Let's create the video-player
component, again, using the Angular CLI tool:
1ng generate component video-player2CREATE src/app/video-player/video-player.component.ts (283 bytes)3UPDATE src/app/app.module.ts (497 bytes)
Now, open the video-player.component.ts
file, and add the following TypeScript code:
1export class VideoPlayerComponent implements OnInit {2 private apiLoaded = false;34 @Input() videoId: string;56 constructor() { }78 ngOnInit(): void {9 if(!this.apiLoaded) {10 const tag = document.createElement('script');11 tag.src = 'https://www.youtube.com/iframe_api';12 document.body.appendChild(tag);13 this.apiLoaded = true;14 }15 }16}
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:
1<script src="https://www.youtube.com/iframe_api"></script>
Next, define the template along with the Property binding through videoId
as follows.
1<youtube-player [videoId]="videoId"></youtube-player>
Using the Video Player Component
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.
1// ... other imports2import { Video } from './model/video';34export class AppComponent {5 videoList: Video[] = [6 {7 title: '[Debugging] Expression has changed after it was checked',8 link: 'https://www.youtube.com/watch?v=O47uUnJjbJc'9 },10 {11 title: '[Debugging] The pipe {name} could not be found',12 link: 'https://www.youtube.com/watch?v=maI2u6Sxk9M'13 }14 ];15}
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.
1<div style="text-align:center">2 <h1>3 Angular YouTube Video Player Demo4 </h1>5</div>6<h2>Select a Video</h2>7<ul>8 <li *ngFor="let video of videoList">9 <h2><a href="#" (click)="selectVideo(video)">{{video.title}}</a></h2>10 </li>11</ul>12<corp-video-player [videoId]="currentVideoId"></corp-video-player>
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.
1export class AppComponent {2 videoList: Video[] = [3 // Objects defined above4 ];56 currentVideoId: string;78 selectVideo(video: Video) {9 const params = new URL(video.link).searchParams;10 this.currentVideoId = params.get('v');11 }12}
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.
The YouTube Video Player API
Properties
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. |
Events
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.
Live Demo
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.