更改html5的源“src”属性对angularjs不起作用

时间:2013-03-18 19:59:18

标签: angularjs html5-audio

我有一个音频文件列表,显示为链接和<audio> html5播放器。每个链接都会调用一个函数来更改<source><audio>标记的src:

<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;
}

我可以看到src正在改变,但没有播放。路径还可以;如果我用其中一条路径初始化src,播放器就可以工作。

我做错了什么?

11 个答案:

答案 0 :(得分:25)

以下是几种有棱角的方法:

1)使用ng-src =而不是src =

角度文档解释了为什么这样有效: http://docs.angularjs.org/api/ng.directive:ngSrc

在编译阶段,angular会扩展元素以包含正确的src =属性。

这将改变HTML5音频元素的src属性,但不幸的是,这还不足以制作新的歌曲。你需要通过调用.play()方法来促使音频元素做某事。

糟透了:(

进一步黑客沿着同样的路径建议在控制器内部进行DOM操作。这通常表明这是错误的解决方案。

更好的解决方案是使用服务!!!

2)使用角度服务的音频

// 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.

  }
});

现在,在您的控制器中,您可以注入“音频”,并做任何您需要做的事情。

例如:

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

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

现在,您可以将'audio'作为参数添加到任何需要的控制器中 更改音乐,并使用此处定义的相同API调用。

作为'服务',整个应用程序只有一个实例。所有对“audio”的调用都指向同一个对象。这对于角度的所有服务都是如此。正是在这种情况下我们需要的。

该服务在应用程序的根文档上创建一个不可见的HTML5元素,因此无需在任何地方的视图上添加标记。当用户导航到不同的视图时,这还有保持播放歌曲的额外好处。

请参阅http://docs.angularjs.org/api/ng。$ document以了解$ document service的定义。

希望有助于交配:)

答案 1 :(得分:20)

即使在使用$ sce.trustAsResourceUrl之后我也遇到了同样的问题,然后我意识到问题出在HTML上。源应该放在音频标签本身:

<audio controls data-ng-src="{{yourTrustedUrl}}" ></audio>

答案 2 :(得分:5)

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

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

这对我有用,你需要消毒你

答案 3 :(得分:4)

ngSrc不适用于AngularJS中的视频,仅适用于图像。我的解决方案是:

在视图中:

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

在控制器中:

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

用你的网址替换我的网址:

$sce.trustAsResourceUrl('your Url');

不要忘记将$sce添加到您的模块中:

angular.module('myApp.controllers', [])
  .controller('MyCtrl1',  function($scope,$http,$routeParams,$sce) {

答案 4 :(得分:2)

我在使用下拉菜单加载视频源时遇到了类似的问题。我发现$scope.$apply();是我需要添加的全部内容。没有时间来接受你的代码并测试这个实现,但我建议你试试这个:

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

关于使用$scope.$apply()处理错误存在一些争议。我认为正确的实施实际上如下:

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

如果songPath返回undefined,这应该会更好地应对;唉,我找不到我学习这个技巧的链接。如果我这样做,我会将其作为对此答案的评论发布。

希望这会有所帮助:)

答案 5 :(得分:1)

您也可以使用:

<div ng-bind-html-unsafe="audioPlayer"></div>

在您的控制器上:

$scope.audioPlayer="<br /><audio controls><source src=\""+ audiosource + "\" type=\"audio/mpeg\"> Your browser does not support the audio element. </audio>"

注意:

  

仅当ngBindHtml指令也是如此时,您应该使用此指令   限制性,当你完全信任内容的来源时   你有约束力。

更多here

答案 6 :(得分:1)

@SteveOC 64的方法涉及创建音频的新实例。如果您已有音频标签,如

<audio id="audio" controls></audio>

您可以尝试以下代码

    app.factory('audio', function($document) {
    var audioElement = $document[0].getElementById('audio');
    audioElement.autoPlay = true; // as per your requirement

    return {
      audioElement: audioElement,

      play: function(filename) {
        audioElement.src = filename;
        audioElement.play();
      },
      resume: function() {
        audioElement.play();
      },
      pause: function() {
        audioElement.pause();
      },
      stop: function() {
        audioElement.pause();
        audioElement.src = audioElement.currentSrc; /** http://stackoverflow.com/a/16978083/1015046 **/
      },
      incVol: function() {
        if (audioElement.volume < 1) {
          audioElement.volume = (audioElement.volume + 0.1).toFixed(2);
        }
        return audioElement.volume;
      },
      decVol: function() {
        if (audioElement.volume > 0) {
          audioElement.volume = (audioElement.volume - 0.1).toFixed(2);
        }
        return audioElement.volume;
      },
      timer: function(callback) {
        audioElement.ontimeupdate = function() {
          callback(audioElement.duration, audioElement.currentTime)
        };
      },
    }
  });

在注入audio工厂后的控制器中,您可以将其称为

 audio.play('/api/resource?resource=' + uri);

如果这是一个事件驱动,就像在播放音频时点击另一个元素

$scope.$apply(function() {
   $scope.audioPlayer = true;
   audio.play('/api/resource?resource=' + uri);
   $scope.isAudioPlaying = true;
});

如果有人在寻找视频工厂:

HTML

<video id="video" controls></video>

app.factory('video', function($document) {
       var videoElement = $document[0].getElementById('video');
       videoElement.autoPlay = true;
       return {
          videoElement: videoElement,
          play: function(filename) {
             videoElement.src = filename;
             videoElement.play();
          },
          resume: function() {
             videoElement.play();
          },
          pause: function() {
             videoElement.pause();
          },
          stop: function() {
             videoElement.pause();
             videoElement.src = videoElement.currentSrc; /** http://stackoverflow.com/a/16978083/1015046 **/
          },
          incVol: function() {
             if(videoElement.volume < 1) {
                videoElement.volume = (videoElement.volume + 0.1).toFixed(2);
             }
             return videoElement.volume;
          },
          decVol: function() {
             if(videoElement.volume > 0) {
                videoElement.volume = (videoElement.volume - 0.1).toFixed(2);
             }
             return videoElement.volume;
          },
          timer: function(callback) {
             videoElement.ontimeupdate = function() {
                callback(videoElement.duration, videoElement.currentTime)
             };
          },
       }
    });

您可以将其作为video.play('/api/resource?resource=' + uri);

调用

希望这有帮助!

答案 7 :(得分:1)

我找到的解决方案是在从ajax调用中获取视频网址后立即加载视频。

var video = angular.element('#video_id');
video.load();

答案 8 :(得分:0)

从未尝试使用audio代码,但src应该进行插值,因此应该在{{}}之间。

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

你有没试过这个?

答案 9 :(得分:0)

更改src后,您还必须加载该文件,因此请尝试在songselect之后添加到您的函数$scope.selectedSongPath = songPath;

$scope.load();

我不知道你的情况是什么$ scope,但load()方法应该在你的音频标签的对象内执行。在简单的JS中,它看起来像这样:

<audio id="audio-tag" controls="controls" preload="none"> //need the ID to get element
    <source type="audio/mpeg" src="{{selectedSongPath}}"/>
</audio>
....
$scope.selectedSongPath = songPath; //you're changing the src
document.getElementById("audio-tag").load(); //here you load the file (you need equivalent in your framework)

希望它有所帮助。

答案 10 :(得分:0)

我之前使用的是ngAudio&amp;面对多个音频一次播放的问题。当试图使用HTML5音频标签时,而不是使用音频和音频。 source为2个标签,只有1个标签解决了我的问题。

<audio controls ng-src='{{trusted_url }}'></audio>