Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing html5's source "src" attribute takes no effect wtih angularjs

I have a list of audio files presented as links and an <audio> html5 player. Each link invokes a function which change the src of the <source> tag within the <audio>:

<audio controls="controls" preload="none">
  <source type="audio/mpeg" src="{{selectedSongPath}}"/>
</audio>

...

<div class="songEntry" ng-repeat="song in songs">
  <a href="" ng-click="songSelect(song.path)">{{song.name}}</a>
</div>

...

$scope.songSelect = function(songPath) {
    $scope.selectedSongPath = songPath;
}

I can see the src changing, but nothing is played. The paths are ok; if I initialize the src with one of the paths, the player works.

What am I doing wrong?

like image 269
user1639431 Avatar asked Mar 18 '13 19:03

user1639431


4 Answers

Here is a couple of angular approaches :

1) Use ng-src= instead of src=

The angular docs explain why this works : http://docs.angularjs.org/api/ng.directive:ngSrc

During compilation stage, angular will expand the element to include the correct src= attribute.

This will change the src attrib of the HTML5 audio element, but unfortunately that is NOT enough to make a new song play. You need to prod the audio element into doing something by calling the .play() method.

Sucks :(

Further hacking along this same path suggests doing DOM manipulation inside the controller. This is generally a sign that this is the wrong solution.

Better solution is to use services !!!

2) Audio using an angular service

// Define a simple audio service 
mpApp.factory('audio',function ($document) {
  var audioElement = $document[0].createElement('audio'); // <-- Magic trick here
  return {
    audioElement: audioElement,

    play: function(filename) {
        audioElement.src = filename;
        audioElement.play();     //  <-- Thats all you need
    }
    // Exersise for the reader - extend this service to include other functions
    // like pausing, etc, etc.

  }
});

Now, in your controller(s), you can inject 'audio', and do whatever you need to do with it.

eg:

function myAstoundingAudioCtrl($scope, audio) { //<-- NOTE injected audio service

    $scope.songSelect = function(songPath) {
        audio.play(songPath);    //     <---  Thats All You Need !
    }
}

You can now add 'audio' as a parameter to any of your controllers that need to be able to change the music, and use the same API call defined here.

Being a 'service', there is only a single instance for the whole application. All calls to 'audio' point to the same object. This is true for all services in angular. Just what we need in this case.

The service creates an invisible HTML5 element on the root document of your application, so there is no need to add an tag on your views anywhere. This has the added bonus of maintaining the playing of the song whilst the user navigates to different views.

See http://docs.angularjs.org/api/ng.$document for the definition of the $document service.

Hope that helps mate :)

like image 77
SteveOC 64 Avatar answered Nov 20 '22 21:11

SteveOC 64


I had the same problem, even after using $sce.trustAsResourceUrl, and then I realized the problem is with the HTML. The source should go in the audio tag itself:

<audio controls data-ng-src="{{yourTrustedUrl}}" ></audio>
like image 23
Oranit Dar Avatar answered Nov 20 '22 20:11

Oranit Dar


<audio ng-src="{{getAudioUrl()}}" audioplayer controls></audio>

$scope.getAudioUrl = function() {
return $sce.trustAsResourceUrl('your url');
};

This is working for me you need to santize you

like image 5
Rahul Shukla Avatar answered Nov 20 '22 21:11

Rahul Shukla


ngSrc doesn't work for video in AngularJS, only work for image. My solution is :

in the view :

        <video controls="controls" name="Video Name" ng-src="{{getVideoUrl()}}"></video>

in the controller:

  $scope.getVideoUrl=function(){
        return $sce.trustAsResourceUrl("media/"+$scope.groupedProjList[$scope.routeId].CONTACTNAME+".mp4");
   };

replace my Url with yours:

$sce.trustAsResourceUrl('your Url');

Don't forget to add $sce to your module:

angular.module('myApp.controllers', [])
  .controller('MyCtrl1',  function($scope,$http,$routeParams,$sce) {
like image 4
stackmave Avatar answered Nov 20 '22 22:11

stackmave