-3

I have read over many people's similar questions and have not found an answer. So I'm asking my own question.

I have been building a feature that allows my users to play all audio tracks on the page they're viewing. However, to make my audio player initially appear on the page, I have to initPlayer() at least once when a user clicks the Play All button.

The problem is, I am using a for loop to iterate over all of the song id's in an array to fill the playlist with songs.

var theids = ids.split(",");

for (var i = 0; i < theids.length; i++) {
  getItem(theids[i], type).done(function(obj) {
    if (obj.status == 'success') {
      mep.mepPlaylistTracks = obj.tracks;
      initPlayer();
      addToPlay(obj.tracks, play);
    }
  });
}

initPlayer() relies on information from my getItem() function to properly initiate the first time. So it has to be placed in this order.

Is there a way I can fire my initPlayer() function only once in my for loop? It is causing my player to reinitiate each time a song is added to the playlist, which is causing performance and visual issues.

Is this sort of thing possible in Javascript?


Edit to add initPlayer() and getItem() functions. I am new to Javascript, any help is appreciated.

// init player
  function initPlayer(){
    $('.app-player').removeClass('hide');
    $('#app').removeClass('hide-player');

    var playlist = $( '.playlist' ).mepPlaylist({
      audioHeight: '40',
      audioWidth: '100%',
      videoHeight: '40',
      videoWidth: '100%',
      audioVolume: 'vertical',
      mepPlaylistLoop: true,
      alwaysShowControls: true,
      mepSkin: 'mejs-audio',
      mepResponsiveProgress: true,
      mepAutoPlay: false,
      mepSelectors: {
        playlist: '.playlist',
        track: '.track',
        tracklist: '.tracks'
      },
      features: [
        //'meplike',
        'mepartwork',
        'mepcurrentdetails',
        'mepplaylist',
        'mephistory',
        'mepprevioustrack',
        'playpause',
        'mepnexttrack',
        'progress',
        'current',
        'duration',
        'volume',
        'mepicons',
        'meprepeat',
        'mepshuffle',
        'mepsource',
        'mepbuffering',
        'meptracklist',
        'mepplaylisttoggle',
        'youtube'
      ],
      mepPlaylistTracks: mep.mepPlaylistTracks
    });

function getItem(id, type){
    return $.ajax({
       type : "post",
       dataType : "json",
       url : ajax.ajax_url,
       data : {action: "ajax_music", id: id, type: type, nonce: ajax.nonce}
    });
  }
akshat
  • 1,219
  • 1
  • 8
  • 24
anthonyCam
  • 360
  • 1
  • 4
  • 21
  • 2
    A "loop" and "once" makes no sense... don't use the loop then you will run the code once... – B001ᛦ May 16 '18 at 12:52
  • This doesn't answer my question. Is it possible? If not, is there a way I can make this work for my script? – anthonyCam May 16 '18 at 12:52
  • 6
    "Doctor, it hurts when I do this!" ... Well, don't do it then. – Sinan Ünür May 16 '18 at 12:53
  • 1
    Can't you run `initPlayer` once at page-load? – tkausl May 16 '18 at 12:53
  • 1
    You're premise that "it has to be placed in this order" is not necessarily true. You haven't shown us what is in `initPlayer` or what `getItem` does so how can we possibly help you? – chazsolo May 16 '18 at 12:54
  • I will edit my post to include those functions... – anthonyCam May 16 '18 at 12:56
  • As far as running initPlayer on page load, my player is only initiated and shown to the user when a play button is pressed. Otherwise, the player is not displayed in the footer of the page. So we only initiate when a button is pressed. – anthonyCam May 16 '18 at 13:01
  • 4
    I think the real solution you're looking for is this: [Wait until all jQuery Ajax requests are done](https://stackoverflow.com/questions/3709597/wait-until-all-jquery-ajax-requests-are-done) – JJJ May 16 '18 at 13:01
  • @JJJ great link, I will read more into that. Thank you. – anthonyCam May 16 '18 at 13:13
  • When in doubt, use a boolean flag and an `if` statement! It's a popular style of programming called "flag-base programming". –  May 16 '18 at 13:31

1 Answers1

3

You could define a boolean outside of the for loop like this:

var theids = ids.split(",");
var once = false;

for (var i = 0; i < theids.length; i++) {
  getItem(theids[i], type).done(function(obj) {
    if (obj.status == 'success') {
      mep.mepPlaylistTracks = obj.tracks;

      if(!once) {
          initPlayer();
          once = true;
      }

      addToPlay(obj.tracks, play);
    }
  });
}
Luke Ramsden
  • 704
  • 4
  • 15
  • 2
    Not sure why this is so heavily downvoted because this does what the OP wants, but there are almost certainly better ways to solve the problem. – JJJ May 16 '18 at 12:57
  • Interesting, thank you. I may be able to work this into my script. – anthonyCam May 16 '18 at 13:02
  • @JJJ I asked a very unpopular question, it seems. So that may be why everything is getting down voted. But I appreciate the help. – anthonyCam May 16 '18 at 13:02
  • 2
    @anthonyCam while this would work, I would still recommend rewriting your code to not need something like this (the link JJJ posted in a comment is a good bet) – Luke Ramsden May 16 '18 at 13:03
  • @anthonyCam Well, the downside of answers like this is that people who ask the question just go for the easiest fix and ignore all warnings and caveats that go with it. And it seems to happen again. – JJJ May 16 '18 at 13:04
  • @LukeRamsden Ok, let me take a look at what JJJ linked and I'll see about rewriting my code altogether. It's a fairly large change I'm making by adding this feature, and it may need to be rewritten. Thank you. – anthonyCam May 16 '18 at 13:05
  • 1
    @JJJ you're right. I'm learning Javascript and I'm prone to accepting easy solutions when they may not be the correct solution. It helps me think though... thanks – anthonyCam May 16 '18 at 13:11