1

I am trying to create a function that gets an array of urls of audio files, then for each audio object it gets its duration and add it to its corresponding html element.

Here is my code:

var audio, musicArray;
musicArray = [
  "https://dl.dropboxusercontent.com/u/33538012/music/music1.mp3", "https://dl.dropboxusercontent.com/u/33538012/music/music2.mp3", "https://dl.dropboxusercontent.com/u/33538012/music/music3.mp3", "https://dl.dropboxusercontent.com/u/33538012/music/music4.mp3", "https://dl.dropboxusercontent.com/u/33538012/music/music5.mp3", "https://dl.dropboxusercontent.com/u/33538012/music/music6.mp3", "https://dl.dropboxusercontent.com/u/33538012/music/music7.mp3", "https://dl.dropboxusercontent.com/u/33538012/music/music8.mp3"
];

audio = new Audio();

addDuration(musicArray);

function addDuration(array) {
  var x = 1;
  $.each(array, function() {
    audio.src = array[x];
    $(audio).on("loadedmetadata", function() { //front
      $("li#row" + x).html(audio.duration);
    });
  });
}

HTML:

<ul>
  <li class="row1"></li>
  <li class="row2"></li>
  <li class="row3"></li>
  <li class="row4"></li>
  <li class="row5"></li>
  <li class="row6"></li>
  <li class="row7"></li>
  <li class="row8"></li>
  <li class="row9"></li>
</ul>

It suppose to show the duration of each song in its right html element. e.g: row1 == musicArray [1]

Edit: this question is entirely different than the possible duplicate ones. even the code and approaches to solve it are different.

Any idea how to make it?

TheGuy
  • 33
  • 4
  • 3
    the code will always update `li#row1` - because x is always 1 – Jaromanda X Feb 12 '16 at 22:39
  • Once you've gotten `x` to increment, see [JavaScript closure inside loops – simple practical example](http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – JJJ Feb 12 '16 at 22:44
  • it's NOT a closure issue - $.each provides a ready made closure – Jaromanda X Feb 12 '16 at 22:44
  • @JaromandaX Yes it is. `x` is outside the `$.each` closure. – JJJ Feb 12 '16 at 22:45
  • @Juhana - x is **not needed** so, technically not a closure issue – Jaromanda X Feb 12 '16 at 22:47
  • @JaromandaX Well if you do something completely different than what's in the question then yes, it will solve the issue, but the code as it is now has a closure issue. – JJJ Feb 12 '16 at 22:50
  • no it isn't, x is 1 and is always 1, so it's not a closure issue, because x never changes - that's your own *"code as it is now"* logic working against you, @Juhana ... and it's not a case of *"do something completely different"* it's a case of *"do what is intended"* – Jaromanda X Feb 12 '16 at 22:53
  • @JaromandaX That's why I said *"Once you've gotten x to increment..."* We can be pretty sure that never incrementing x was not a conscius decision by the OP. – JJJ Feb 12 '16 at 22:56
  • @Juhana - well if you do something completely different ... I could argue that **x** was intended to be the first argument of the `$.each` callback – Jaromanda X Feb 12 '16 at 22:58

2 Answers2

1

With a little re-arrangement, your code can do what you want

var musicArray;
musicArray = [...];

addDuration(musicArray);

function addDuration(array) {
    $.each(array, function (index, src) { // index is 0...array.length - 1
        var audio = new Audio(); // new audio object for each bit of audio
        $(audio).on("loadedmetadata", function () { //front
            $("li#row" + (index+1)).html(audio.duration); // index+1 because your li's are 1...n, and array indexes are 0...(arry.length-1)
        });
        audio.src = src; // add the source AFTER adding the event listener - maybe not necessary, but what if the event fires before you have a listener for it?
    });
}

I've added comments in the code, hope that's enough to help

but ... some explanation anyway

the function called by $.each is called with several arguments

function(index, arrayitem, ...) - so, you don't need to use musicArray[index] inside the function, as it's provided by arrayitem argument

you li's are numbered 1...9 (even though you only have 8 urls, but that's fine) ... the index in an array goes from 0...7 in this case (8 items) - hence why the (index + 1)

Jaromanda X
  • 53,868
  • 5
  • 73
  • 87
  • Thanks for your answer. It is understandable, but unfortunately does not work. [This is the demo version of your code](https://jsfiddle.net/schtftzd/3/). Furthermore, is there any other way that I could keep the `Audio` object outside the loop or remove/destroy it as soon as the `duration` is taken? since I have another Audio object in the page, having this object twice makes problems in some browsers. – TheGuy Feb 13 '16 at 01:57
  • sorry, I put the audio.src = src in the WRONG PLACE - edited ... see [working fiddle](https://jsfiddle.net/schtftzd/4/) – Jaromanda X Feb 13 '16 at 03:21
-1

The array starts from 0 and not from 1, so when you initialize x=1, you are accessing only from the 2nd item in "musicArray". Your "x" never changes and always remains 1, you need to increment it after each iteration. quick fix will be:

function addDuration(array) {

  $.each(array, function(x,item) {
    var audio = new Audio();
    audio.src = item;
    $(audio).on("loadedmetadata", function() { //front
      $("li#row" + (x+1)).html(audio.duration);
    });
  });
avi.tavdi
  • 305
  • 2
  • 4
  • 17