prime
prime

Reputation: 2074

Angular2 : Asynchronous upload array of files

I'm trying to upload an array of files using FileReader which are base64 encoded and stored in an array for further processing. I'm struggling to understand the pattern I need to create in order to ensure all files have been uploaded because I have to wait for the onload event handler to fire. For example;

If I pass an array of files to the following function it will resolve the promise before the files are actually uploaded.

localUploads( event ) : any {

    var response = [];

    return new Promise( function(resolve, reject) {

        //Retrieve all the files from the FileList object
        var files = event.target.files;
        var response = [];

        if (files) {

            for (var i=0, f; f=files[i]; i++) {

                var r = new FileReader();

                r.onload = (function(f) {

                    return function(e) {

                        let contents = e.target['result'];

                        let file = {
                            name: f.name,
                            asset: contents,
                            private: false
                        };

                        console.log('we are pushing into the array');
                        response.push( file );
                    };

                })(f);


            }   
            resolve( response );
        }

        r.readAsText(f);
    });
}

Can anybody please advise a novice?

Many thanks.

Upvotes: 2

Views: 620

Answers (1)

smoksnes
smoksnes

Reputation: 10851

It's all about resolving the promise at the right time. Currently you resolve it when the loop is done, but that doesn't mean that all the items have been processed. I haven't used FileReader, but you should be able to do something like this:

localUploads( event ) : any {

    var response = [];

    return new Promise(function(resolve, reject) {

        //Retrieve all the files from the FileList object
        var files = event.target.files;
        var response = [];

        if (files) {

            for (var i=0, f; f=files[i]; i++) {

                var r = new FileReader();
                r.onload = function(e) { // Possible clean-up?
                    let contents = e.target['result'];

                    let file = {
                        name: f.name,
                        asset: contents,
                        private: false
                    };

                    console.log('we are pushing into the array');
                    response.push( file );
                    if(response.length == files.length)
                    {
                        // Everything is done. Resolve the promise.
                        resolve( response );
                    }
                };
                // Moved here to be able to access r and f variables
                r.readAsText(f);
            }   
        }
    });
}

Or the old way using $q.

    var response = [];
    var dfd = $q.defer();

    //Retrieve all the files from the FileList object
    var files = event.target.files;
    var response = [];

    if (files) {
        for (var i=0, f; f=files[i]; i++) {
            var r = new FileReader();
            r.onload = function(e) { // Possible clean-up?
                let contents = e.target['result'];

                let file = {
                    name: f.name,
                    asset: contents,
                    private: false
                };

                console.log('we are pushing into the array');
                response.push( file );
                if(response.length == files.length)
                {
                    // Everything is done. Resolve the promise.
                    dfd.resolve(response);
                }
            };
            // Moved here to be able to access r and f variables
            r.readAsText(f);
        }   
    }
    else {
        // Possible resolve promise here to?
    }
    return dfd.promise;

Note that you might also want to handle the possible errors. If one of the files isn't completed sucessfully the promise will never be resolved.

You might need to resolve the promise in onloadend instead of onload. I really cannot figure it out from the docs.

var r = new FileReader();
r.onload = function(e) {
    if(response.length == files.length)
    {
        // Everything is done. Resolve the promise.
        dfd.resolve(response);
    }
}

Upvotes: 1

Related Questions