web-dev-qa-db-fra.com

La modification de l'attribut source "src" de html5 n'a aucun effet avec angularjs

J'ai une liste de fichiers audio présentés sous forme de liens et un <audio> lecteur html5. Chaque lien invoque une fonction qui change le src du <source> tag dans le <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;
}

Je peux voir le src changer, mais rien n'est joué. Les chemins sont corrects; si j'initialise le src avec l'un des chemins, le lecteur fonctionne.

Qu'est-ce que je fais mal?

29
user1639431

Voici quelques angular:

1) Utilisez ng-src = au lieu de src =

Les documents angular expliquent pourquoi cela fonctionne: http://docs.angularjs.org/api/ng.directive:ngSrc

Pendant la phase de compilation, angular développera l'élément pour inclure l'attribut src = correct.

Cela changera l'attribut src de l'élément audio HTML5, mais malheureusement ce n'est PAS suffisant pour faire jouer une nouvelle chanson. Vous devez inciter l'élément audio à faire quelque chose en appelant la méthode .play ().

Suce :(

Un piratage plus poussé sur ce même chemin suggère de faire une manipulation DOM à l'intérieur du contrôleur. C'est généralement un signe que ce n'est pas la bonne solution.

La meilleure solution est d'utiliser des services !!!

2) Audio utilisant un service angular

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

  }
});

Maintenant, dans votre ou vos contrôleurs, vous pouvez injecter du "son" et faire tout ce que vous devez faire avec.

par exemple:

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

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

Vous pouvez maintenant ajouter 'audio' en tant que paramètre à n'importe lequel de vos contrôleurs qui doivent pouvoir changer la musique et utiliser le même appel d'API défini ici.

Étant un "service", il n'y a qu'une seule instance pour toute l'application. Tous les appels à "audio" pointent vers le même objet. Cela est vrai pour tous les services en angulaire. Exactement ce dont nous avons besoin dans ce cas.

Le service crée un élément HTML5 invisible sur le document racine de votre application, il n'est donc pas nécessaire d'ajouter une balise sur vos vues n'importe où. Cela a l'avantage supplémentaire de maintenir la lecture de la chanson pendant que l'utilisateur navigue vers différentes vues.

Voir http://docs.angularjs.org/api/ng . $ Document pour la définition du service $ document.

J'espère que ça aide mon pote :)

25
SteveOC 64

J'ai eu le même problème, même après avoir utilisé $ sce.trustAsResourceUrl, puis j'ai réalisé que le problème venait du HTML. La source doit aller dans la balise audio elle-même:

<audio controls data-ng-src="{{yourTrustedUrl}}" ></audio>
19
Oranit Dar
<audio ng-src="{{getAudioUrl()}}" audioplayer controls></audio>

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

Cela fonctionne pour moi, vous devez désinfecter votre

5
Rahul Shukla

ngSrc ne fonctionne pas pour la vidéo dans AngularJS, ne fonctionne que pour l'image. Ma solution est:

dans la vue:

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

dans le contrôleur:

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

remplacez mon URL par la vôtre:

$sce.trustAsResourceUrl('your Url');

N'oubliez pas d'ajouter $sce à votre module:

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

J'ai eu un problème similaire lors du chargement des sources vidéo avec un menu de sélection déroulant. J'ai trouvé que $scope.$apply(); était tout ce que j'avais besoin d'ajouter. Vous n'avez pas eu le temps de prendre votre code et de tester cette implémentation, mais je vous recommande d'essayer ceci:

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

Il y a un différend concernant l'utilisation de $scope.$apply() concernant la gestion des erreurs. Je pense que la bonne mise en œuvre est en fait la suivante:

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

Ceci est censé mieux fonctionner si songPath renvoie undefined; hélas, je ne trouve pas le lien où j'ai appris cette astuce. Si je le fais, je le posterai en tant que commentaire à cette réponse.

J'espère que cela t'aides :)

2
Jeshua

La solution que j'ai trouvée consiste à charger la vidéo dès que vous obtenez l'URL vidéo d'un appel ajax.

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

Vous pouvez également utiliser ceci:

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

Sur votre manette:

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

Attention:

Vous ne devez utiliser cette directive que si la directive ngBindHtml est trop restrictive et lorsque vous faites entièrement confiance à la source du contenu auquel vous vous liez.

plus ici

1
Shote

L'approche de @SteveOC 64 traite de la création d'une nouvelle instance de l'audio. Si vous avez déjà une balise audio comme

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

Vous pouvez essayer le code ci-dessous

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

Et dans votre contrôleur après avoir injecté audio usine, vous pouvez l'appeler comme

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

s'il s'agit d'un événement, comme en lecture audio en cliquant sur un autre élément

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

Et si quelqu'un cherche l'usine vidéo:

HTML

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

Usine

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

Et vous pouvez l'invoquer comme video.play('/api/resource?resource=' + uri);

J'espère que cela t'aides!

1
Arvind

J'utilisais ngAudio plus tôt et je fais face à un problème de plusieurs audio joués à la fois. Lorsque j'ai essayé d'utiliser une balise audio HTML5, au lieu d'avoir l'audio et la source comme 2 balises, une seule balise a résolu mon problème.

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

0
Swapnil Chincholkar

Après avoir modifié le src, vous devez également charger ce fichier, essayez donc d'ajouter à votre fonction songselect après $scope.selectedSongPath = songPath; Ce qui suit:

$scope.load();

Je ne sais pas ce que $ scope est dans votre cas, mais la méthode load() devrait être exécutée à l'intérieur de l'objet de votre balise audio. Dans JS simple, cela ressemblerait à ça:

<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)

J'espère que ça aide.

0
sobol6803

Jamais essayé avec la balise audio, mais src doit être interpolé, donc il doit être entre {{}}.

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

Avez-vous déjà essayé cela?

0
Caio Cunha