Multiple instances of jQuery HTML5 audio player

I created a custom HTML5 audio player using jQuery according to the tutorial given here: http://neutroncreations.com/blog/building-a-custom-html5-audio-player-with-jquery/

My script looks like this:

    jQuery(document).ready(function() {

        audio = jQuery('div#artificial-brothers audio').get(0);
        loadingIndicator = jQuery('div#artificial-brothers #loading');
        positionIndicator = jQuery('div#artificial-brothers #handle');
        timeleft = jQuery('div#artificial-brothers #timeleft');

        if ((audio.buffered != undefined) && (audio.buffered.length != 0)) {
            jQuery(audio).bind('progress', function() {
                var loaded = parseInt(((audio.buffered.end(0) / audio.duration) * 100), 10);
                loadingIndicator.css({width: loaded + '%'});
            });
        } else {
            loadingIndicator.remove();
        }

        jQuery(audio).bind('timeupdate', function() {

            var rem = parseInt(audio.duration - audio.currentTime, 10),
                    pos = (audio.currentTime / audio.duration) * 100,
                    mins = Math.floor(rem/60,10),
                    secs = rem - mins*60;

            timeleft.text('-' + mins + ':' + (secs < 10 ? '0' + secs : secs));
            //if (!manualSeek) { 
                positionIndicator.css({width: pos + '%'});
            // }
            //if (!loaded) {
            //  loaded = true;

            jQuery('div#artificial-brothers #gutter').slider({
                value: 0,
                step: 0.01,
                orientation: "horizontal",
                range: "min",
                max: audio.duration,
                animate: true,          
                slide: function() {             
                    manualSeek = true;
                },
                stop:function(e,ui) {
                    manualSeek = false;         
                    audio.currentTime = ui.value;
                }
            });

        }).bind('play',function(){
            jQuery('div#artificial-brothers #playtoggle').addClass('playing');      
        }).bind('pause ended', function() {
            jQuery('div#artificial-brothers #playtoggle').removeClass('playing');       
        });     

        jQuery('div#artificial-brothers #playtoggle').click(function() {            
            if (audio.paused) { audio.play();   } 
            else { audio.pause(); }         
        });

        jQuery('div#artificial-brothers #stoptoggle').click(function() {            
            if (audio.play) {   audio.pause();  } 
            audio.currentTime = 0;      
        });
});

      

My problem is that I need to run multiple instances of the mentioned player on the same page and I can't seem to achieve that. I tried to copy / paste the script and change the id (artificial siblings), but then only the script will actually work. Any ideas on how to summon a player more than once on a page would be great!

// Casper

EDIT: According to the info provided by @charlieftl, my code now looks like this:

jQuery(document).ready(function() {

    jQuery('.player').each(function(){

        var container = jQuery(this);
        var audio = container.find('audio').get(0);
        var loadingIndicator = container.find('.loading');
        var positionIndicator = container.find('.handle');
        var slider = container.find('.gutter');
        var timeleft = container.find('.timeleft');

        if ((audio.buffered != undefined) && (audio.buffered.length != 0)) {
            jQuery(audio).bind('progress', function() {
                var loaded = parseInt(((audio.buffered.end(0) / audio.duration) * 100), 10);
                loadingIndicator.css({width: loaded + '%'});
            });
        } else {
           loadingIndicator.remove();
        }

        jQuery(audio).bind('timeupdate', function() {

            var rem = parseInt(audio.duration - audio.currentTime, 10),
                    pos = (audio.currentTime / audio.duration) * 100,
                    mins = Math.floor(rem/60,10),
                    secs = rem - mins*60;

            timeleft.text('-' + mins + ':' + (secs < 10 ? '0' + secs : secs));
            //if (!manualSeek) { 
                positionIndicator.css({width: pos + '%'});
            // }
            //if (!loaded) {
            //  loaded = true;

            slider.slider({
                value: 0,
                step: 0.01,
                orientation: "horizontal",
                range: "min",
                max: audio.duration,
                animate: true,          
                slide: function() {             
                    manualSeek = true;
                },
                stop:function(e,ui) {
                    manualSeek = false;         
                    audio.currentTime = ui.value;
                }
            });
        });

        container.find('.playtoggle').click(function() {            
            if (audio.paused) { audio.play();   } 
            else { audio.pause(); }         
        });

        container.find('.stoptoggle').click(function() {            
            if (audio.play) {   audio.pause();  } 
            audio.currentTime = 0;      
        });

        jQuery(audio).bind('play',function(){
            container.find('.playtoggle').addClass('playing');      
        });

        jQuery(audio).bind('pause ended', function() {
            container.find('.playtoggle').removeClass('playing');       
        }); 
    });

});

      

+3


source to share


1 answer


Judging from your use of jQuery selectors, I suspect that you are repeating the element id in your page. The ID must be unique, so most of your selectors should only reflect the actual ID of the element. If an element has an ID, there is never a reason to run the selector at a higher level ... the ID itself is the most efficient selector choice

From your code:

    jQuery('div#artificial-brothers #loading');

      

Should be:

    jQuery('#loading');

      



To work around your problem, you need to change the duplicate identifier for the class. Wrap each of the html instances for your audio in a generic class container

   <div class="audio_wrap">
      <!--All html associated with a single audio-->
    </div>

      

Now you can iterate over all of these instances with $.each

. Within a loop, you are always looking only for elements within that instance.

Below is a complete rewrite of all your code, but an example is enough to set up a template that will allow you to keep instances isolated from each other.

    $('.audio_wrap').each(function(){

            /* cache the container instance in a variable*/
            var $container=$(this);
            /* searching within the container instance for each 
            component insulates multiple instances on page*/

            var $audio= $container.find('audio');
            var $slider=$container.find('.sliderClass');

            /*now events will only be bound to this instance*/ 
            $audio.bind('play',function(){
                /* within event callbacks keep searches within the main container element*/                     
                $container.find('.playtoggleClass').addClass('playing'); 

            });
    });

      

0


source







All Articles