Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use Angular variables as the source of an audio tag?

I am trying to do the following:

<div ng-repeat="audio in event.audios">
    <audio ng-src="/data/media/{{audio}}" controls></audio>
</div>

But when I load the view, the {{audio}} variable is not parsed but hardcoded into the source as is. However, if for example, I place that same variable outside of the audio tag it renders the name of the audio file correctly. I've tried using both src and ng-src to no avail.

Is there a way to get the variable to work within an audio tag?

Thanks in advance.

like image 727
Hols Avatar asked May 14 '14 15:05

Hols


2 Answers

I'm not all that familiar with the ngSrc directive outside of using it on images, but it might require an img tag somewhere in the source.

Try this:

<div ng-repeat="audio in event.audios">
    <audio ng-attr-src="/data/media/{{audio}}" controls></audio>
</div>

The ng-attr- directive can be used for any attribute that doesn't have a specific role in angular. You can read more about it on this page.

Update, I was wrong.

I created a jsfiddle and found the actual error that was occurring.

You're getting an error from the sce service. See the SO question here.

The solution is to use $sce.trustAsResourceUrl().

Example:

angular.module('AudioTest', [])
.controller('AudioTestCtrl', function($scope, $sce) {
    $scope.event = { 'audios': [
        $sce.trustAsResourceUrl('/data/media/test1'),
        $sce.trustAsResourceUrl('/data/media/test2')
    ]};
});

Here's the fiddle.

Update #2

If you don't want to set the url as hard coded or loop through after you get a response from the server, you can use a custom filter to accomplish what you're looking for. This method does not use interpolation, which is where the error is being thrown.

JS:

angular.module('AudioTest', [])
.filter('trustedAudioUrl', function($sce) {
    return function(path, audioFile) {
        return $sce.trustAsResourceUrl(path + audioFile);
    };
})
.controller('AudioTestCtrl', function($scope) {
    $scope.event = { 'audios': ['test1', 'test2']};
});

HTML:

<div ng-app="AudioTest">
    <div ng-controller="AudioTestCtrl">
        <div ng-repeat="audio in event.audios">
            <audio ng-src="/data/media/ | trustedAudioUrl:audio)" controls></audio>
        </div>
    </div>
</div>

And the new fiddle.

like image 85
Joe Avatar answered Sep 25 '22 03:09

Joe


Ok, thanks to theJoeBiz's input and some thinking around I solved this by making a directive, here is the code:

app.directive('audios', function($sce) {
  return {
    restrict: 'A',
    scope: { code:'=' },
    replace: true,
    template: '<audio ng-src="{{url}}" controls></audio>',
    link: function (scope) {
        scope.$watch('code', function (newVal, oldVal) {
           if (newVal !== undefined) {
               scope.url = $sce.trustAsResourceUrl("/data/media/" + newVal);
           }
        });
    }
  };
});

Then on the template I used it like so:

<div ng-repeat="audio in event.audios">
    <div audios code="audio"></div>
</div>

It is all working fine now.

like image 20
Hols Avatar answered Sep 23 '22 03:09

Hols