Leveraging AngularJS and YouTube API to trigger a script upon completion of video playback

I am trying to implement a function that triggers when a YouTube video finishes playing. The structure of my code is as follows:

<div class="row">
    <div class="col-md-6">

        <div id="player" ts-video-player></div>

    </div>
</div>

Afterwards, I decided to define a directive like this:

.directive('tsVideoPlayer', ['$state', function ($state) {


    // autoplay video
    function onPlayerReady(event) {
        console.log('autoplay');

        event.target.playVideo();
    }

    // handle video end
    function onPlayerStateChange(event) {
        if (event.data === 0) {
            console.log('finished');

            alert('done');
        }
    }

    return {
        restrict: 'A',
        link: function (scope, element) {

            console.log('setting up player');
            console.log(element.attr('id'));

            function onYouTubePlayerAPIReady() {

                console.log('Creating player');

                var player = new YT.Player(element.attr('id'), {
                    height: '390',
                    width: '640',
                    videoId: 'GE2BkLqMef4',
                    events: {
                        'onReady': onPlayerReady,
                        'onStateChange': onPlayerStateChange
                    }
                });
            }
        }
    }
}])

I have included this script in the index.html file:

<script src="http://www.youtube.com/player_api"></script>

However, nothing seems to be happening. My console logs indicate that the 'setting up video player' message and the player id are being displayed, but onYouTubePlayerAPIReady is never triggered.

Can someone provide me with assistance?

Answer №1

One possible explanation is that the function you have defined is nested within a directive linking function closure, making it inaccessible to the YouTube API. To solve this issue, you can move the function to the window object using one of the following methods:

1) Create a global function and trigger an event

Place the function in the global scope just before the closing body tag, then access the Angular rootScope element to broadcast an event:

<script>
  function onYouTubePlayerAPIReady(){
    angular.element(document).ready(function(){
       var rootScope = angular.element(document).injector().get('$rootScope');
       rootScope.$broadcast('onYouTubePlayerAPIReady');
    });
  }
</script>
<script src="http://www.youtube.com/player_api"></script>

Lastly, subscribe to this event in your directive.

.directive('tsVideoPlayer', [function () {


    // autoplay video
    //....

    return {
        restrict: 'A',
        link: function (scope, element) {
           //....
            scope.$on('onYouTubePlayerAPIReady', function() {
              console.log('Creating player');
               var player = new YT.Player(element.attr('id'), {
                  .....
                });
            });
        }
    }
}]);

Demo


2) Check for Status within the directive itself

Another approach is to check for the YT object and its loaded status in the directive, and take appropriate actions based on the result.

.directive('tsVideoPlayer', ['$window', function ($window) {

    return {
        restrict: 'A',
        link: function (scope, element) {
            console.log(YT.loaded);

            if (!YT) {
                console.log('playerNotLoaded');
                $window.onYouTubePlayerAPIReady = onPlayerRady;
            } else if (YT.loaded) {
                onPlayerRady();
            } else {
                YT.ready(onPlayerRady);
            }

            function onPlayerRady() {
                console.log('Creating player');
                var player = new YT.Player(element.attr('id'), {
                    height: '390',
                    width: '640',
                    videoId: 'GE2BkLqMef4',
                    events: {
                        'onReady': onPlayerReady,
                            'onStateChange': onPlayerStateChange
                    }
                });
            }

            console.log(YT.loaded);
            // autoplay video
            function onPlayerReady(event) {
                console.log('autoplay');

                event.target.playVideo();
            }

            // when video ends
            function onPlayerStateChange(event) {
                if (event.data === 0) {
                    console.log('finished');

                    alert('done');
                }
            }

        }
    }
}]);

Demo

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What's preventing me from using the left click function on my published blog post?

This is my first time creating a blogger template and everything seems to be working correctly. However, I have encountered one problem. For some reason, I am unable to left click on my blog post. I have not installed any right/left click disabler and I&a ...

What is the best way to execute a series of asynchronous JavaScript functions one after the other?

As I attempt to call the following functions in succession, their return does not always happen in the expected order. Upon discovering asynchronous functions and the concept of using "callbacks," I realized there might be a solution for executing these f ...

Employing state management in React to toggle the sidebar

A working example of a sidebar that can be toggled to open/close using CSS, HTML and JavaScript is available. Link to the Example The goal is to convert this example to React by utilizing states instead of adding/removing CSS classes. To ensure the side ...

What is causing the poor color and contrast of equirectangular backgrounds in Three.js, and what steps can be taken to improve them?

Using Three.js for a website project with a construction company, I created 360° photospheres using my Google Pixel 5. The client also requested a 3D representation of one of their projects, making Three.js the ideal solution. Comparison: Original photo ...

The ID data from my axios.delete request is not properly transferring to the req.body, causing issues with deleting from mySQL

Currently, I am utilizing Axios to manage the requests in my application. Upon testing with PostMan, it has been confirmed that my DELETE request is functioning properly. However, when implementing the code for the front end, I encountered a 404 error duri ...

Validate if a string in JQuery contains a specific substring

How can I determine if one string contains another string? var str1 = "ABCDEFGHIJKLMNOP"; var str2 = "DEFG"; What function should I utilize to check if the string str1 includes the string str2? ...

Looking for a way to determine in JavaScript whether the last item in an array is a number or not? Keep in mind that the last element could be either a number or a string, depending

console.log("case 1") var event = "Year 2021"; console.log(typeof(parseInt(event.split(" ").pop())) === "number"); console.log("case 2") var event = "Year mukesh"; console.log(typeof(parseInt(event.split(" ").pop())) === "number"); console.log("case 3") va ...

Issues with image loading in Next JS and Cloudinary

I'm currently delving into the world of Next JS and attempting to convert my app into a static site. In doing so, I've opted to utilize Cloudinary for image processing; however, I'm encountering issues with the images not displaying. Next JS ...

How to iterate through an array of objects in Javascript and extract an array of strings

I am dealing with an array of objects that looks like this: [{"key":"aaa","value":true},{"key":"bbb","value":false},{"key":"ccc","value":true}] My goal is to iterate through it and extract an array containing only the keys: ["aaa", "bbb", "ccc"] I am u ...

PhantomJS struggles to render web pages that utilize both Angular and Websockets

Encountering a scenario where certain intricate pages (complex due to nested views) are failing to render in PhantomJS while using . The versions I am currently running: Phantom 1.9.8 Websocket 1.2.0 Angular 1.3.1 I suspect the issue lies with websoc ...

Transforming date and timezone offset into an isoDate format using moment.js

When retrieving data from the API, I encounter Date, Time, and Offset values in separate columns. My goal is to obtain an ISO date while maintaining the original date and time values. const date = "2019-04-15" const time = "13:45" const ...

Unable to render $scope on the page

Upon querying a database, I am retrieving all the images associated with the user who is currently logged in. The code for this operation can be found in the uploadController: UserImage.get($scope.user_id) .success(function(data) { $scope.userA ...

jQuery validation - Date not validated on Safari, only works on Chrome

Issue: jQuery validation is not functioning properly on Safari, but it works fine on Google Chrome and Firefox. The content management system (CMS) responsible for handling the form signup requires the date to be in the format YYYY-MM-DD. However, most pe ...

Incorporating jQuery Masonry for seamless overlapping effect while implementing infinite scroll

I've developed a script that enables infinite scrolling on my website: $(document).ready(function() { function getLastId() { var lastID = $(".element:last").attr("id"); $.post("2HB.php?action=get&id=" + lastID, ...

Use HTML to showcase an image that dynamically changes based on the outcome of a query function

Hello there, I hope my inquiry is clear enough. I apologize for reaching out as I am unsure where to begin and what exactly I should be focusing on. Currently, I have an image displayed in an HTML page like this: <div id="tag_sunrise_sunset"><p ...

Unable to retrieve object property in JavaScript

Having some trouble accessing the javascript object property. const one = data[acti][0]?.Original?.Form.sortorder It seems that sortorder is not available on that object. After logging data[acti][0]?.Original?.Form, the Form object displays these values ...

How can we animate elements inside partials when utilizing a single ng-view in our index file, specifically with AngularJS 1.2?

A few weeks ago, I was 80% done building an app that heavily relied on jQuery for animations. However, I decided to start over and rebuild it from scratch using AngularJS. Now, I'm at a point where I want to incorporate some of the animations I had o ...

Encountering difficulty in interpreting angular function in JSON

Here is an example of my Json data: "review": { { "message_bar_text": "Please review your transaction details carefully. If you need to make changes after confirming, please call <a ng-click=\"callCSC(number)\">1-800-325-6000</a>. } ...

The React application is unable to communicate with my Express application in a production environment, despite functioning properly during development

Currently, I am attempting to make a basic get request to my express backend located at mywebsite.com/test. The expected response from the server should be {"test": "test"}. While this is working perfectly fine in development on localho ...

Discovering identical objects in two arrays in Angular using TypeScript is a breeze

I've hit a roadblock with a TypeScript problem in my Angular service. I have an array of ingredients: private ingredients: Ingredient[] = [ new Ingredient('farina', 500), new Ingredient('burro', 80), new Ingredient('ucc ...