17

I'm trying to implement a video element in an angular JS app and the ng-src won't read the scope variable

I'm using 1.2.0-rc.2

<!DOCTYPE html>
<html ng-app="ngView">

<head>
   <script src="http://code.angularjs.org/1.2.0-rc.2/angular.min.js"></script>

   <script>
   var app = angular.module('ngView', []);
   function MyControl($scope){
      $scope.file = '1234.mp4';
   }
  </script>
  </head>
  <body ng-controller="MyControl">
      <video controls  ng-src="http://www.thebigdot.com/{{file}}"></video>
  </body>
</html>

If I use a much older version AngularJS lib, it works.

cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.3/angular.min.js (works)

Is this a bug in the latest release or has it been disabled on purpose? What is the work around ?

5
  • Works for me jsfiddle.net/gjCDt Commented Oct 15, 2013 at 3:50
  • @ChrisNicola it does not work, take a look at the URL in the element viewer. Commented Oct 15, 2013 at 4:12
  • Huh, you're right, it looks like a bug with <video> tags. Works with <image> I'd suggest submitting the jsFiddle example to Github. It throws a JS error too. Commented Oct 15, 2013 at 4:22
  • it works with images probably because they do not require a "trusted value" in the src. Commented Oct 15, 2013 at 4:32
  • See this SO answer: stackoverflow.com/questions/21884666/… Commented Oct 28, 2014 at 15:26

5 Answers 5

33

Angular 1.2 ships with Strict Contextual Escaping (SCE) enabled by default. You need to tweak your code slightly to make it work.

HTML

Change the markup so that the ng-src binds to a variable and not a URL + variable as you had it setup before:

<video controls ng-src="{{videoUrl}}"></video>

JavaScript

Add $sce to inject the SCE provider and use the $sce.trustAsResourceUrl method to set videoUrl.

function MyControl($scope, $sce) {
    var videoUrl = 'http://www.thebigdot.com/1234.mp4';
    $scope.videoUrl = $sce.trustAsResourceUrl(videoUrl);
}

Here's a JS Bin demo of this setup in action.

Sign up to request clarification or add additional context in comments.

5 Comments

This still looks like a bug to me since they mention that they don't use these for a[href] and img[src] values but it is being used for the video tag. Perhaps video/audio tags need to be considered here as well.
This example nicely explains how to hardcode an absolute path into your controller, but I'm still struggle to figure out how to iterate through a JSON file that's been bound to a $scope; i.e. something more like OP's original example: ng-src="thebigdot.com{{file}}" For example, say I have A LOT of videos to dynamically populate inside my template based on an id I am sending to the router via $routeParams Any suggestions would be helpful.
Oh, actually I was able to solve the issue by referring to the answer here: stackoverflow.com/questions/23405162/…
But your demo doesn't work although the video url is fine.
nice i want exactly this but it's for only one video from Json response. in my case i want to display multiple video so please any one can help me?
6

after a bit of debugging I found that the error is this:

Error: [$interpolate:noconcat] Error while interpolating: http://www.thebigdot.com/{{file}} Strict Contextual Escaping disallows interpolations that concatenate multiple expressions when a trusted value is required.  See [http://docs.angularjs.org/api/ng.$sce][1] 

http://errors.angularjs.org/1.2.0-rc.2/$interpolate/noconcat?p0=http%3A%2F%2Fwww.thebigdot.com%2F%7B%7Bfile%7D%7D
    at http://code.angularjs.org/1.2.0-rc.2/angular.js:78:12
    at $interpolate (http://code.angularjs.org/1.2.0-rc.2/angular.js:6953:17)
    at attrInterpolateLinkFn (http://code.angularjs.org/1.2.0-rc.2/angular.js:5367:27)
    at nodeLinkFn (http://code.angularjs.org/1.2.0-rc.2/angular.js:5121:13)
    at compositeLinkFn (http://code.angularjs.org/1.2.0-rc.2/angular.js:4640:15)
    at nodeLinkFn (http://code.angularjs.org/1.2.0-rc.2/angular.js:5115:24)
    at compositeLinkFn (http://code.angularjs.org/1.2.0-rc.2/angular.js:4640:15)
    at compositeLinkFn (http://code.angularjs.org/1.2.0-rc.2/angular.js:4643:13)
    at publicLinkFn (http://code.angularjs.org/1.2.0-rc.2/angular.js:4549:30)
    at http://code.angularjs.org/1.2.0-rc.2/angular.js:1157:27 <video controls="" ng-src="http://www.thebigdot.com/{{file}}"> angular.js:7861

this article explains what is going on and how to disable the Strict Contextual Escaping: http://docs.angularjs.org/api/ng.$sce

3 Comments

I managed to get it working by not concatenating the values, just format the URL in the service rather than the view. <video controls ng-src="{{file}}" >
For new people finding this question, if you're using SCE (enabled by default on modern versions of Angular) you'll need to add the foreign domain to the whitelist. This came up in another question: stackoverflow.com/a/21884995/384693
Whitelisting is the safest solution. You don't want to use $sce.trustAsResourceUrl willy-nilly unless you're absolutely sure you can trust the resulting URL (i.e. that by interpolating a user controlled value you won't enable them to enter a malicious value that could compromise the security of your app).
2

I build this directive

app.directive('loadAudio', function($parse) {
  return {
    restrict: 'EA',
    scope: {
        source: '=',       
    },
    template: '<audio />',
    link: function(scope, iElement, iAttrs) {

      scope.$watch('source', function(value) {
        var audio = iElement.find('audio');

        audio.attr('src',  value);
      }, true);
    }
  }
});

And next is what I write on the template

<load-audio source="your_src" ></load-audio>

Comments

0

I did simple hack before I found previous post. Somebody could found this useful

HTML :

<div id="videoTag"></div>

Controller.js

document.getElementById("videoTag").innerHTML = "<video width='auto' height='auto' controls autoplay src=" + $scope.details.preview + ">Your browser does not support video</video>";

Comments

0

I had the same problem with version 1.5.0 of angular. When I changed version (I took the 1.4.8 release) my problem was solved.

.controller('MainCtrl',['$scope','$stateParams','DepartementFactory',
        function($scope,$stateParams,DepartementFactory) {
            $scope.currentDate=new Date();
            DepartementFactory.getDepartements().then(function(data){
               $scope.departements=data;
               $scope.departements.logo="work"; 
            });
        }
    ]
)
<div class="work">
    <a>
        <img src="images/{{departements.logo}}" class="media" alt=""/>
        <div class="caption">
            <div class="work_title">
                <h1>{{departements.libelle}}</h1>
            </div>
        </div>
    </a>
</div>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.