0

I'm trying to display a div when Vimeo video reached the end using ng-show but I can get it to work.

Related part of the controller responsible for ng-show looks like

    'use strict';

    myApp.controller('videoController', [
        '$scope',
        '$routeParams',
        '$rootScope',
        '$location',
        '$log',
        function(
            $scope, 
            $routeParams, 
            $rootScope, 
            $location,
            $log
        )
        {

            var player = new Vimeo.Player('player');
            player.on('timeupdate', function(data) {

            $scope.videoFinished = false;

            $scope.currentPlayDuration = (data.percent * 100).toFixed(1);

            if($scope.currentPlayDuration==100.0){
                $scope.videoFinished = true;
                $log.debug('Video finished: ' + $scope.videoFinished);
                $scope.apply();
            }

        });
    }
]);

and a view for that part:

<div class="row" ng-show="videoFinished">Thank you for watching!</div>

Part where related controller is defined:

myApp.config(['$routeProvider','$locationProvider',function($routeProvider,$locationProvider) {
    $routeProvider
    .when('/video', {
        templateUrl: 'video.html',
        controller: 'videoController'
    })  
    .otherwise({
        redirectTo: '/'
    });

When I run video to the end console will show

Video finished: true

but a div from above is not displayed.

Any clue?

JackTheKnife
  • 3,795
  • 8
  • 57
  • 117
  • 1
    Can you post a more complete code sample to ensure the `div` is within scope of the controller? – Ben Nov 06 '17 at 17:29
  • 1
    `player.on('timeupdate', function(data) {` probably doesnt trigger a digest cycle - try calling `$scope.apply()` at the end (this isn't the ideal solution, just seeing if it fixes the problem) – tymeJV Nov 06 '17 at 17:30
  • @tymeJV that solution is not working – JackTheKnife Nov 06 '17 at 17:35
  • @Ben OP updated with more code – JackTheKnife Nov 06 '17 at 17:39
  • try printing {{videoFinished}} in template to ensure it is with in the scope. – Hareesh Nov 06 '17 at 17:43
  • 1
    Try working with object literal, instead of `$scope.videoFinished = false;` try `$scope.video = {finished: false};`, update it using `$scope.video.finished = true;` and in the view, change it to `ng-show="video.finished"` (Or use the `controllerAs` syntax) - You should keep the `$scope.apply();` or inject `$timeout` and use it instead – Alon Eitan Nov 06 '17 at 17:45
  • Could you post the code where ng-controller is specified? – Gagan Bansal Nov 06 '17 at 17:47
  • I agree with @GaganBansal comment, we need to see more of the view, in the meanwhile i'm VTC with the "why isn't this code working?" reason, as your code **should** work with the details you provided – Alon Eitan Nov 06 '17 at 17:49
  • @GaganBansal `ng-controller` is specified in the myApp.config `$routeProvider` – JackTheKnife Nov 06 '17 at 17:49
  • Another idea - Make sure the element is not hidden by the video player, remove the `ng-show=".."` part and make sure it's visible – Alon Eitan Nov 06 '17 at 17:52
  • @AlonEitan when `ng-show` is removed it displays that message but all the time – JackTheKnife Nov 06 '17 at 17:55
  • @JackTheKnife OK, so please try my [suggestion](https://stackoverflow.com/questions/47142475/ng-show-not-triggered-on-value-true#comment81235576_47142475), instaed of `$scope.apply();` try to inject `$timeout` to the dependencies list, and the wrap `$scope.video.finished = true;` with `$timeout` (Like: `$timeout(function() { $scope.video.finished = true; });`), long shot, but that's the only thing I can think of, unless i'm missing something else ofcourse – Alon Eitan Nov 06 '17 at 17:57
  • This is still not a [mcve]. A single `div` doesn't show where this is placed in your HTML tree, or what else that `div` could be affected by; for example, since you are using a primitive property, it could be affected by other `ng-if`, `ng-show`, `ng-hide`, `ng-repeat`, etc. also present on the page. – Claies Nov 06 '17 at 18:05
  • Is it the routing that’s wrapping your view in the controller? If so you need to access the correct scope with $ctrl.videoFinished – Ben Nov 06 '17 at 18:07
  • @Claies there is nothing else except Vimeo player div above div mentioned above. – JackTheKnife Nov 06 '17 at 18:14
  • 1
    Shouldn't that be `$scope.$apply()`? – JLRishe Nov 06 '17 at 18:25
  • ok, so as others have said, there isn't anything at all obviously wrong with your code here, and without some way to reproduce your problem, the question has turned into guesses thrown into comments. – Claies Nov 06 '17 at 18:41
  • @JLRishe That did the job. To all - thanks for your helping. I know it sounds frustrating that it should to work as is and I have expected as such of simple code is going to work that way but it wasn't – JackTheKnife Nov 06 '17 at 19:29

1 Answers1

1

The video player's events happen outside of AngularJS's digest cycle, so you have to manually initiate a digest cycle with $scope.$apply() so that it can pick up the changes:

player.on('timeupdate', function(data) {

    $scope.videoFinished = false;

    $scope.currentPlayDuration = (data.percent * 100).toFixed(1);

    if ($scope.currentPlayDuration == 100.0) {
        $scope.videoFinished = true;
        $log.debug('Video finished: ' + $scope.videoFinished);
        $scope.$apply();
    }
});

As a side note, it's not considered good practice to have your controllers interact directly with non-Angular components in the page. The appropriate place to do that would generally be in a custom directive.

JLRishe
  • 99,490
  • 19
  • 131
  • 169
  • 1
    This is a very helpful read: https://www.thinkful.com/projects/understanding-the-digest-cycle-528/ – Stone Nov 06 '17 at 20:52
  • @JLR Can you provide an example (link) to a custom directive for non-Angular code which can be helpful in my case? – JackTheKnife Nov 07 '17 at 03:10