Search code examples
htmlangularangular8

Angular 8 - Is there a way to bind to a video element to determine when it is loaded/starts playing?


Given:

<video poster="assets/videos/poster.png"
       #videoPlayer 
       onloadedmetadata="this.muted = true">
     <source src="assets/videos/video.mp4" type="video/mp4">
</video>

And in Angular:

...

public videoLoaded: boolean = false;

...

How can I bind videoLoaded to update once the video starts playing? (or is loaded) I've looked online and saw some older jquery implementations that seem to not be working in newer versions of chrome and want to know the latest way on how to accomplish this

Thanks


Solution

  • What you could do is make a reference to the video player itself with Angular's ViewChild and check if it's clicked.

    @ViewChild('videoPlayer') videoPlayer: ElementRef;
    
    videoClicked = false;
    
    startVideo(): void {
        this.videoClicked = true;
        this.videoPlayer.nativeElement.play();
    }
    

    The startVideo() method will be used inside the HTML to trigger the change. The additional paragraph is used to see the change.

    <video (click)="startVideo()" width="400"
           #videoPlayer>
         <source src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" type="video/mp4">
    </video>
    
    <p>Video clicked: {{videoClicked}}</p>
    

    See this StackBlitz as an example of above behaviour.

    Edit
    A better way to do this is to use HTMLMediaElement's onplaying and loadeddata event. See MDN for documentation on onplaying and documentation on loadeddata. In normal JavaScript it would look like this:

    const video = document.querySelector('video');
    
    video.onplaying = (event) => {
      console.log('Video is no longer paused.');
    };
    

    In Angular, there are some small changes required. The HTML can stay pretty clean.

    <video controls width="400"
           #videoPlayer>
         <source src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" type="video/mp4">
    </video>
    
    <p>Video loaded: {{dataLoaded}}</p>
    <p>Video started: {{videoStarted}}</p>
    

    The biggest changes are in the component, ngAfterViewInit checks if the element is there after view has been initialised. The loadeddata event is fired when the frame at the current playback position of the media has finished loading (so ready to play). Next to that, you can access the element's onplaying event to check if the video is not paused.

    @ViewChild('videoPlayer') videoPlayer: ElementRef;
    
    dataLoaded = false;
    videoStarted = false;
    
    ngAfterViewInit() {
        this.videoPlayer.nativeElement.onloadeddata = (event) => {
            console.log('Video data is loaded.');
            this.dataLoaded = true;
        };
    
        this.videoPlayer.nativeElement.onplaying = (event) => {
            console.log('Video is no longer paused.');
            this.videoStarted = true;
        };
    }
    

    Here's a StackBlitz example to show this example.