0

I'm using Filepicker.io to store images. I'm trying to get the image's metadata using their filepicker.stat() function. However, while it allows me to work with the metadata internally like so:

filepicker.stat(InkBlobs[i], { width: true, height: true }, function(metadata){ console.log(JSON.stringify(metadata)) });

I can't get the metadata out of that anonymous function. What I'd like to do is something like this:

for(i = 0; i < InkBlobs.length; i++)
{
    filepicker.stat(InkBlobs[i], { width: true, height: true }, function(metadata){ InkBlobs[i].add(JSON.stringify(metadata)); });
}

This obviously doesn't work (the InkBlobs[i].add( ... )) part, so how can I capture that metadata and include it with the other data located in the array? The array contents can each be JSON.stringify()'d.

1 Answer 1

1

First, I assume that the callback receives metadata as an argument; that's missing from the code in the question, but I will assume that below.

You can do basically what you wrote, you just have to manage i slightly differently and have a place to store it. As this is JavaScript, you can just add your own property to the InkBlob instances, but that's typically a bit dangerous (in case you conflict with something non-public, or they add something similar to the objects in the next release, etc.).

First let's deal with i:

for(i = 0; i < InkBlobs.length; i++)
{
    filepicker.stat(InkBlobs[i], { width: true, height: true }, makeCallback(i));
}
function makeCallback(index) {
    return function(metadata){
        InkBlobs[index].add(JSON.stringify(metadata));
        // This bit ^^ is still theoretical
    };
}

Now, instead of closing over i, our callback closes over index, which is the argument we passed to makeCallback when we called it in the loop. Where i changes before the callback occurs, index does not.

You can also use ES5's bind if the this that the callback sees doesn't have to be controlled by stat:

for(i = 0; i < InkBlobs.length; i++)
{
    filepicker.stat(InkBlobs[i], { width: true, height: true }, function(index, metadata){
        InkBlobs[index].add(JSON.stringify(metadata));
        // This bit ^^ is still theoretical
    }.bind(null, i));
}

Note that the argument i we pass bind shows up in front of any supplied by stat (the first argument to bind, null in my example, is what sets this during the callback).

I'll use bind from here on out because it's more concise.

Now we have to store the metadata with the inkblobs. Here's one way:

var data = [];
var count = 0;
for(i = 0; i < InkBlobs.length; i++)
{
    filepicker.stat(InkBlobs[i], { width: true, height: true }, function(index, metadata){
        data[index] = {
            blob:     InkBlobs[index],
            metadata: metadata // No reason to stringify it that I know of, but you could
        };
        ++count;
        if (count === InkBlobs.length) {
            useTheNewArray();
        }
    }.bind(null, i));
}

Note that we wait to call useTheNewArray until we've seen the callback for all blobs. Also note that we don't just push to the new array, because they could arrive out of order (in theory). Of course, if the order doesn't matter, push away and you don't need the count variable anymore.

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

5 Comments

Thanks for the detailed response! Just to clarify, where you call useTheNewArray();, do you mean a direct copy over the previous InkBlobs array?
Also, if I'm not using the bind() method, wouldn't I also have to pass the metadata into makeCallback()?
For some reason or another, this isn't actually working for me. I tried both with the bind() and without (the former method and the latter) and the data array just stays empty. I guess it could be with however I'm trying to useNewArray(), but I'm not really sure what else you could do aside from straight up copying or returning the array.
@rar: By "use" I mean...use. Index into it and do things with the objects it has in it, instead of using InkBlobs. No, you don't have to pass metadata into makeCallback -- makeCallback's job is to create function that stat will call with the metadata argument.
Ah okay. I found it confusing in that I don't actually USE the InkBlobs array until after the for loop is complete. I just wanted to modify the contents of each object by adding the metadata to each one before using it outside of the for loop.

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.