Search code examples
javascriptangularjsangularangularjs-directiveangularjs-scope

handle APlayer through angular js - play music dynamically


I am new to angular js - trying to build an audio play using Aplayer

Task:- 1. Play music dynamically 2. On click of album get json data and add to aplayer

(function() {
      'use strict';
    
      angular.module('app', []);
    
      angular
      .module('app')
      .directive('aplayer', aplayer);
    
      function aplayer() {
        return {
          restrict: 'AC',
          link: function(scope, element, attrs) {
            // `element` is the angular element the directive is attached to 
            // APlayer need the native one
            var nativeElement = element[0];
            var ap1 = new APlayer({
              element: nativeElement,
              narrow: false,
              autoplay: true,
              showlrc: false,
              mutex: true,
              theme: '#e6d0b2',
              preload: 'metadata',
              mode: 'circulation',
              music: {
                title: attrs["playerTitle"],
                author: attrs["playerAuthor"],
                url: attrs["playerUrl"],
                pic: attrs["playerPic"]
            }
        });
            ap1.on('play', function() {
              console.log('play');
          });
            ap1.on('play', function() {
              console.log('play play');
          });
            ap1.on('pause', function() {
              console.log('pause');
          });
            ap1.on('canplay', function() {
              console.log('canplay');
          });
            ap1.on('playing', function() {
              console.log('playing');
          });
            ap1.on('ended', function() {
              console.log('ended');
          });
            ap1.on('error', function() {
              console.log('error');
          });
    
        }
    };
    }
    
    })();
<!doctype html>

<html lang="en" ng-app="app">

<head>
  <meta charset="utf-8">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/aplayer/1.6.0/APlayer.min.js"></script>
  <script src="script.js"></script>
</head>

<body>
  <div class="aplayer" 
       data-player-title="Preparation" 
       data-player-author="Hans Zimmer/Richard Harvey" 
       data-player-url="http://devtest.qiniudn.com/Preparation.mp3"
       data-player-pic="http://devtest.qiniudn.com/Preparation.jpg"></div>
</body>

</html>

How to pass music files dynamically to Aplayer on click of an album.


Solution

  • According to Aplayer source code, it's not possible to replace music track or playlist dynamically. API only expose setMusic method which allow to choose track index in music playlist.

    To display your albums, you need to load them first using a service which will call your tracks API.

    Once loaded, you can inject them to your aplayer directive and choose the index of the track to play.

    Here is a sample snippet with :

    • a musicService to handle your music library

    • a TrackController to load and display your music library

    • a modified aplayer directive to handle tracks and current track index

    Note: I'm using free music from Free Music Archive for this demo.

    (function() {
      'use strict';
    
      angular.module('app', []);
    
      angular
        .module('app')
        .factory('musicService', ['$timeout', musicService])
        .controller('TracksController', ['$scope', 'musicService', TracksController])
        .directive('aplayer', aplayer);
    
    
      function musicService($timeout) {
        return {
          loadTracks: function() {
            // Simulate a 1500 ms $http api call
            return $timeout(function() {
              return [{
                  title: 'Procrastinating in the Sun',
                  author: 'The Spin Wires',
                  url: 'https://freemusicarchive.org/music/download/e7fee95c2d7f7b1ea8d4260850a6128842eb85a4',
                  pic: 'https://freemusicarchive.org/file/images/artists/The_Spin_Wires_-_20170510154106040.jpg?width=290&height=290'
                },
                {
                  title: 'осоле',
                  author: 'Kosta T',
                  url: 'https://freemusicarchive.org/music/download/0e4d722be7bd7ca334970b5407b3e5654b95f7a2',
                  pic: 'https://freemusicarchive.org/file/images/tracks/Track_-_2017050264944176?method=crop&width=290&height=290'
                }
              ];
            }, 1500);
    
    
          }
        }
      }
    
      function TracksController($scope, musicService) {
    
        $scope.loadingTracks = true;
        $scope.showPlayer = false;
    
        musicService.loadTracks()
          .then(function(tracks) {
            // Once tracks are loaded, update scope
            $scope.tracks = tracks;
            $scope.loadingTracks = false;
          });
    
        $scope.play = function(trackIndex) {
          $scope.trackIndex = trackIndex;
          $scope.showPlayer = true;
        }
      }
    
    
      function aplayer() {
        return {
          restrict: 'AC',
          scope: {
            tracks: '=',
            trackIndex: '='
          },
          link: link
        };
    
        function link(scope, element, attrs) {
    
          var player = new APlayer({
            narrow: true,
            mode: "order",
            music: scope.tracks
          });
    
          // Watch for trackIndex changes
          scope.$watch(
            function(scope) {
              // Return the "result" of the watch expression as it's more efficient
              // @see http://www.bennadel.com/blog/2852-understanding-how-to-use-scope-watch-with-controller-as-in-angularjs.htm
              return scope.trackIndex;
            },
            function(currentIndex, previousIndex) {
              // As currentIndex is an integer, if(0) equals if(false)
              // But we can use a regular expression to check it's an integer
              if (/\d/.test(currentIndex)) {
                player.setMusic(parseInt(currentIndex));
                player.play();
              }
            });
    
        }
      }
    
    })();
    <!doctype html>
    
    <html lang="en" ng-app="app">
    
    <head>
      <meta charset="utf-8">
      <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/aplayer/1.6.0/APlayer.min.js"></script>
      <style>
        ul li {
          list-style-type: none;
        }
        
        ul li * {
          vertical-align: middle
        }
      </style>
    </head>
    
    <body ng-controller="TracksController">
    
      <div ng-if="loadingTracks">Loading tracks, please wait...</div>
      <ul>
        <li ng-repeat="track in tracks">
          <img ng-src="{{track.pic}}" width="64" height="64">
          <button ng-click="play($index)">Play</button> {{track.author}} / {{track.title}}
        </li>
      </ul>
    
      <div ng-if="tracks && showPlayer">
        <h2>Now playing</h2>
        <div>{{tracks[trackIndex].author}} / {{tracks[trackIndex].title}}</div>
    
        <div class="aplayer" data-tracks="tracks" data-track-index="trackIndex"></div>
      </div>
    
    </body>
    
    </html>