20

AngularJS ng-src doesn't work with HTML5 Video element in this fiddle: http://jsfiddle.net/FsHah/5/

Looking at video element, the src tag is being populated with the correct src uri, but the video doesn't play.

Is this not supported in AngularJS, what is the workaround for this?

qais
  • 1,808
  • 3
  • 20
  • 31

10 Answers10

55

Just Create a Filter:

app.filter("trustUrl", ['$sce', function ($sce) {
        return function (recordingUrl) {
            return $sce.trustAsResourceUrl(recordingUrl);
        };
    }]);

In View File:

<audio src="{{Your_URL | trustUrl}}" audioplayer controls></audio>
Sdd Sdei
  • 773
  • 6
  • 10
8

This currently seems like a bug in AngularJS: https://github.com/angular/angular.js/issues/1352

Replacing source with <video ng-src="{{src}}" controls></video> seems to be the only way at the moment to at least load a source into the video. Hopefully someone comes around to either fix this or provide a workaround of some sort.

georgeawg
  • 48,608
  • 13
  • 72
  • 95
dk123
  • 18,684
  • 20
  • 70
  • 77
8

To play the video I just used the following method have a button called play and in the ng-click of the button you have to write this

 var myVideo = document.getElementsByTagName('video')[0];
myVideo.src = vidURL;
myVideo.load();
myVideo.play();

to play video in ng-repeat use index. hope it helps.

kavinhuh
  • 739
  • 1
  • 9
  • 30
  • 1
    Thanks you, this worked for me! In my situation, I wanted the video to play automatically, so I did it this way using a JS timeout. – JackKalish Apr 13 '16 at 18:18
5

Remove source tag from video tag and try this..

<video controls preload=auto ng-src="{{videoURL| trustUrl}}" poster="{{thumbnailUrl}}"></video>

and in your angular app create a filter like this

 app.filter("trustUrl", function($sce) {
            return function(Url) {
                console.log(Url);
                return $sce.trustAsResourceUrl(Url);
            };
        });
saurabh yadav
  • 153
  • 1
  • 7
4

My response is a few years late, but this is for anyone who is still looking for a solution. I had the same issue. I remembered that Youtube displays their embedded videos using a different tag - iframe. I applied the properties I wanted and it worked.

<iframe width="560" height="300" ng-src="{{ video }}" frameborder="0" allowfullscreen controls></iframe>

For anyone new to AngularJS, the {{ video }} is a $scope.video variable in the control for this page that has the path to the video.

Soubriquet
  • 3,100
  • 10
  • 37
  • 52
2

workaround

in controller

$scope.mp3 = "http://download.jw.org/audio.mp3"

$scope.$watch('mp3', function() {
       $("audio").attr("src",$scope.mp3)
   });

html:

<audio id="mejs" type="audio/mp3" controls="controls"></audio>
Dario
  • 29
  • 2
  • 1
    angular equivalent, without jQuery dependency: `angular.element(document.getElementById('audio_element_id')).attr('src', $scope.mp3)` – JoshuaDavid Feb 08 '15 at 03:44
2

This is a default security precaution in AngularJS. Please see the details: https://docs.angularjs.org/api/ng/service/$sce

To disable the 'Strict Contextual Escaping' compeletly you can define this in your app.js file

angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
      // Completely disable SCE.  For demonstration purposes only!
      // Do not use in new projects.
      $sceProvider.enabled(false);
    });

However they don't recommend. But you may use for a spesific controller like this:

var myAppControllers = angular.module('myAppControllers', []); ScorpAppControllers.controller('HomeCtrl', ['$scope', 'Home',    function ($scope, Home) {
$scope.Home = Home.query(); }]).config(function($sceProvider) {
$sceProvider.enabled(false); });
georgeawg
  • 48,608
  • 13
  • 72
  • 95
nesimtunc
  • 849
  • 7
  • 28
2

I think what's happening is Angular fills in the src attributes after the and elements have been added to the page, so the browser sees the elements with broken URLs. I worked around it using ng-if:

        <video muted ng-if="foo" loop autoplay>
            <source ng-src="{{foo.media.mp4.url}}">
            <source ng-src="{{foo.media.webm.url}}" type="video/webm">
            <img ng-src="{{foo.media.gif.url}}">
        </video>

This makes the element tied to the existence of foo, which is a scope variable being populated via AJAX call.

Seán Hayes
  • 4,060
  • 4
  • 33
  • 48
  • Put the `ngIf` in each `source` element and check if the `ngSrc` value is indeed set: `` This should work as well, and you don't need to maintain an additional `foo` variable. – user1438038 Jul 25 '22 at 14:03
1

You can use ng-media module.

angular.module('app', ['media'])
    .controller('mainCtrl', function($scope) {
        
        $scope.videoSources = [];
        
        $scope.loadVideos = function() {
            $scope.videoSources.push('http://www.w3schools.com/html/mov_bbb.mp4');
            $scope.videoSources.push('http://www.w3schools.com/html/mov_bbb.webm');
        };
    });
<div ng-app='app'>
  <div ng-controller='mainCtrl'>        
    <video html5-video='{{ videoSources }}'
        autoplay='true' controls='true'>
    </video>
    <br>
    <a href="#" ng-click='loadVideos()'>Load videos</a>
  </div>
</div>

<script src="https://code.angularjs.org/1.3.15/angular.js"></script>
<script src="http://caitp.github.io/ng-media/ng-media.js"></script>

Plunker.

Muhammad Reda
  • 26,379
  • 14
  • 93
  • 105
0

Just use vanilla js (regular javascript) to make this work. If you are listening to events like onended you might want to reconsider using $scope.$apply().

My example:

document.getElementById('video').src = $scope.videos[$scope.videoindex];
Marc
  • 48
  • 1
  • 8