0

I know this is probably a duplicate but I just can't figure out how to do it (trust me i've searched, i've tried to fiddle around with the code). I have the following code which is building a table of files that you drag and dropped in to the app.

function CreateTrackTable (data, length) {

    var fs = require('fs'),
        mm = require('musicmetadata'),
        i  = 0;

    for (i; i < length; ++i) { 

        var mimeType = data.dataTransfer.files[i].type;

        if (mimeType == "audio/mp3" || mimeType == "audio/x-m4a"){

                FilePath = data.dataTransfer.files[i].path;
                var parser = mm(fs.createReadStream(FilePath));

            parser.on('metadata',  function (result) {

                if (result.picture.length == 0) {
                    $("#track-table").append('<tr path="'+ FilePath +'"><td></td></tr>');
                }else{
                    var picture = base64ArrayBuffer(result.picture[0].data);
                    $("#track-table").append('<tr path="'+ FilePath +'"><td></td></tr>');     
                }
            });
        }
    } 
}

The Problem is that the FilePath variable is accessible however it "prints-out" always the same path, not the one respected to the loop i.

The app is builded with nodo-webkit everything quite works and this is the only problem I can't figure out.

Thanks for the help!

David Reinberger
  • 540
  • 3
  • 11
  • the keyword you are looking for is `closure` http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example BTW, here you should use `var FilePath ` to not set variable on global scope even using a closure will fix this issue anyway – A. Wolff Mar 06 '14 at 20:33
  • See if you can get the path you want from the metadata in `result`. `.on()` is an event handler, so it is asynchronous and not linear. – js1568 Mar 06 '14 at 20:39
  • Here something that should work : http://jsfiddle.net/EUh3m/ (should have used pasteBin... well too late). It is doing a closure like the link A. Wolff posted. – Karl-André Gagnon Mar 06 '14 at 20:39

1 Answers1

3

Each function created inside the loop closes over the same FilePath (i.e. they don't each get their own copy), which means that they'll each see whatever value that variable has whenever they execute. To make this work how you expect, you need to arrange it so that they do each get their own copy. Since JavaScript variables are scoped to the nearest enclosing function, the way to do that is to wrap the function creation in an immediately-invoked function that receives the desired value as an argument:

(function(FilePath) {
    parser.on('metadata',  function (result) {
        if (result.picture.length == 0) {
            $("#track-table").append('<tr path="'+ FilePath +'"><td></td></tr>');
        } else {
            var picture = base64ArrayBuffer(result.picture[0].data);
            $("#track-table").append('<tr path="'+ FilePath +'"><td></td></tr>');     
        }
    });
})(FilePath);

In this case, each new function closes over a new FilePath, which produces the wanted result.

Wayne
  • 59,728
  • 15
  • 131
  • 126