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!

3
  • the keyword you are looking for is closure stackoverflow.com/questions/750486/… BTW, here you should use var FilePath to not set variable on global scope even using a closure will fix this issue anyway Commented Mar 6, 2014 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. Commented Mar 6, 2014 at 20:39
  • Here something that should work : jsfiddle.net/EUh3m (should have used pasteBin... well too late). It is doing a closure like the link A. Wolff posted. Commented Mar 6, 2014 at 20:39

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks! this work - just there is a missing bracket at the end - }(FilePath)); - this is works flawlessly.
Understanding why this worked is the key to using closures effectively.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.