4

I am trying to write code to upload multiple files using SP2013 REST API. I referred the MSDN article "upload single file using REST API".
But I am having problem when I modified the code to upload multiple files.
I debugged the code and found addFileToFolder() function is not getting called.
Can anyone help in figuring out the issue?

HTML

<input id="getFile" type="file" multiple="multiple"/><br />
<input id="addFileButton" type="button" value="Upload" onclick="upload()"/>

Code

function upload(){
    $.when(uploadFiles()).done(function(){
        alert('all files uploaded');
    });
}
var fileCount = 0;
function uploadFiles() {
    debugger;
    var serverRelativeUrlToFolder = 'SiteAssets';
    var fileInput = jQuery('#getFile');

    var serverUrl = _spPageContextInfo.webAbsoluteUrl;

    var def = $.Deferred();

    var promises = [];

    for(var i = 0; i < window.document.getElementById('getFile').files.length; i++){
            promises.push(function(){
            var getFile = getFileBuffer(i);
            getFile.done(function(resultArray){
                var addFile = addFileToFolder(resultArray);
                addFile.done();
                addFile.fail(onError);
            });
            getFile.fail(onError);
        });
    }

    $.when.apply($, promises).then(function(){def.resolve()});

    return def.promise();

    function getFileBuffer(i){
        var deferred = $.Deferred();
        var reader = new FileReader();
        reader.onLoadend = function(e){
            deferred.resolve(e.target.result);
        };
        reader.onError = function(e){
            deferred.reject(e.target.error);
        }
        reader.readAsArrayBuffer(fileInput[0].files[i]);
        return deferred.promise();
    }

    function addFileToFolder(resultArray){
        var i = fileCount;
        if(i == (fileInput[0].files.length - 1)){
            fileCount = 0;
        }
        fileCount++;
        fileName = fileInput[0].files[i].name;
        var fileCollectionEndPoint = String.format(
            "{0}/_api/web/getfolderbyserverrelativeurl('{1}')/files" + 
            "/add(overwrite=true, url='{2}')",
            serverUrl, serverRelativeUrlToFolder, fileName
        );

        return $.ajax({
            url: fileCollectionEndPoint,
            type: "POST",
            data: resultArray,
            processData: false,
            headers: {
                "accept":"application/json;odata=verbose",
                "X-RequestDigest":$("__REQUESTDIGEST").val(),
                "content-length":resultArray.byteLength
            }
        });
    }
}        
// Display error messages. 
function onError(error) {
    a = error;
    alert(error.responseText);
}
  • Is addFileToFolder() not getting called even once? Are you seeing any error alerts? – Submits Aug 28 '15 at 9:21
  • No. I also tried putting alert() at the beginning of function but it is getting called – Yayati Aug 28 '15 at 9:25
  • Please be more specific - "No" to which of my two questions? Which function did you put alert() at the beginning of? Did you mean "but it is NOT getting called"? – Submits Aug 28 '15 at 9:29
  • Neither the addFileToFolder() is getting called even once nor I am seeing any error alert. I put alert() in the very first line of addFileToFolder() function. – Yayati Aug 28 '15 at 9:36
  • Put an alert() before for(var ..., before var getFile ..., before getFile.done ... and before var addFile .... Then you'll know exactly where your problem is. – Submits Aug 28 '15 at 9:41
7

Some how I figured out the way of using deferred and promises in correct manner. Following code runs perfectly as required.

function upload() {
    // Define the folder path for this example.
    var serverRelativeUrlToFolder = 'SiteAssets';

    // Get test values from the file input and text input page controls.
    var fileInput = jQuery('#getFile');
    var newName = jQuery('#displayName').val();
    var fileCount = fileInput[0].files.length;
    // Get the server URL.
    var serverUrl = _spPageContextInfo.webAbsoluteUrl;
    var filesUploaded = 0;
    for(var i = 0; i < fileCount; i++){
        // Initiate method calls using jQuery promises.
        // Get the local file as an array buffer.
        var getFile = getFileBuffer(i);
        getFile.done(function (arrayBuffer,i) {

            // Add the file to the SharePoint folder.
            var addFile = addFileToFolder(arrayBuffer,i);
            addFile.done(function (file, status, xhr) {
                //$("#msg").append("<div>File : "+file.d.Name+" ... uploaded sucessfully</div>");
                filesUploaded++;
                if(fileCount == filesUploaded){
                    alert("All files uploaded successfully");
                    //$("#msg").append("<div>All files uploaded successfully</div>");
                    $("#getFile").value = null;
                    filesUploaded = 0;
                }
            });
            addFile.fail(onError);
        });
        getFile.fail(onError);

    }

    // Get the local file as an array buffer.
    function getFileBuffer(i) {
        var deferred = jQuery.Deferred();
        var reader = new FileReader();
        reader.onloadend = function (e) {
            deferred.resolve(e.target.result,i);
        }
        reader.onerror = function (e) {
            deferred.reject(e.target.error);
        }
        reader.readAsArrayBuffer(fileInput[0].files[i]);
        return deferred.promise();
    }

    // Add the file to the file collection in the Shared Documents folder.
    function addFileToFolder(arrayBuffer,i) {
    var index = i;

        // Get the file name from the file input control on the page.
        var fileName = fileInput[0].files[index].name;

        // Construct the endpoint.
        var fileCollectionEndpoint = String.format(
                "{0}/_api/web/getfolderbyserverrelativeurl('{1}')/files" +
                "/add(overwrite=true, url='{2}')",
                serverUrl, serverRelativeUrlToFolder, fileName);

        // Send the request and return the response.
        // This call returns the SharePoint file.
        return jQuery.ajax({
            url: fileCollectionEndpoint,
            type: "POST",
            data: arrayBuffer,
            processData: false,
            headers: {
                "accept": "application/json;odata=verbose",
                "X-RequestDigest": jQuery("#__REQUESTDIGEST").val(),
                "content-length": arrayBuffer.byteLength
            }
        });
    }
}

// Display error messages. 
function onError(error) {
    alert(error.responseText);
}
  • nice, this helped me a lot! But you should have a look again at your promise pattern for async methods. You are using it the wrong way. You should't use nested async methods. instead linearize it. – Sebastian Schütze Nov 25 '15 at 15:44
  • you should also include the reference from where you got the code: msdn.microsoft.com/en-us/library/office/dn769086.aspx – Sebastian Schütze Nov 25 '15 at 15:54
  • Yayati,Your answer is very helpful, could you please let me know how can we insert custom column values along with document upload in document library? Thanks – V-K Jul 1 '16 at 6:49
1
//For updating custom column while uploading file you use following code with yayati's code

    function upload() {
        // Define the folder path for this example.
        var serverRelativeUrlToFolder = 'SiteAssets';

        // Get test values from the file input and text input page controls.
        var fileInput = jQuery('#getFile');
        var newName = jQuery('#displayName').val();
        var fileCount = fileInput[0].files.length;
        // Get the server URL.
        var serverUrl = _spPageContextInfo.webAbsoluteUrl;
        var filesUploaded = 0;
        for (var i = 0; i < fileCount; i++) {
            // Initiate method calls using jQuery promises.
            // Get the local file as an array buffer.
            var getFile = getFileBuffer(i);
            getFile.done(function (arrayBuffer, i) {

                // Add the file to the SharePoint folder.
                var addFile = addFileToFolder(arrayBuffer, i);
                addFile.done(function (file, status, xhr) {
                   //Get ID of File uploaded 
                    var getfileID = getItem(file.d);
                    getfileID.done(function (fResult) {
                        var colObject = new Object();
                        colObject["FileType"] = fileType;
                        var changeItem = updateFileMetadata(libraryName, fResult.d, colObject);
                        changeItem.done(function (result) {
                            filesUploaded++;
                            if (fileCount == filesUploaded) {
                                alert("All files uploaded successfully");
                                //$("#msg").append("<div>All files uploaded successfully</div>");
                                $("#getFile").value = null;
                                filesUploaded = 0;
                            }
                        });
                        changeItem.fail(function (result) {

                        });

                    }, function () { });

                });
                addFile.fail(onError);
            });
            getFile.fail(onError);

        }

        // Get the local file as an array buffer.
        function getFileBuffer(i) {
            var deferred = jQuery.Deferred();
            var reader = new FileReader();
            reader.onloadend = function (e) {
                deferred.resolve(e.target.result, i);
            }
            reader.onerror = function (e) {
                deferred.reject(e.target.error);
            }
            reader.readAsArrayBuffer(fileInput[0].files[i]);
            return deferred.promise();
        }

        // Add the file to the file collection in the Shared Documents folder.
        function addFileToFolder(arrayBuffer, i) {
            var index = i;

            // Get the file name from the file input control on the page.
            var fileName = fileInput[0].files[index].name;

            // Construct the endpoint.
            var fileCollectionEndpoint = String.format(
                    "{0}/_api/web/getfolderbyserverrelativeurl('{1}')/files" +
                    "/add(overwrite=true, url='{2}')",
                    serverUrl, serverRelativeUrlToFolder, fileName);

            // Send the request and return the response.
            // This call returns the SharePoint file.
            return jQuery.ajax({
                url: fileCollectionEndpoint,
                type: "POST",
                data: arrayBuffer,
                processData: false,
                headers: {
                    "accept": "application/json;odata=verbose",
                    "X-RequestDigest": jQuery("#__REQUESTDIGEST").val(),
                    "content-length": arrayBuffer.byteLength
                }
            });
        }
    }

    // Display error messages. 
    function onError(error) {
        alert(error.responseText);
    }

    function updateFileMetadata(libraryName, item, colPropObject) {
        var def = jQuery.Deferred();

        var restSource = siteUrl + "/_api/Web/Lists/getByTitle('" + libraryName + "')/Items(" + item.Id + ")";
        var jsonString = "";

        var metadataColumn = new Object();
        metadataColumn["type"] = item.__metadata.type;
        //columnArray.push(metadataColumn);
        if (colPropObject == null || colPropObject == 'undefined')// For library having no column properties to be updated
        {
            colPropObject = new Object();
        }
        colPropObject["__metadata"] = metadataColumn;
        jsonString = JSON.stringify(colPropObject);
        var dfd = jQuery.Deferred();
        jQuery.ajax(
        {
            'url': restSource,
            'method': 'POST',
            'data': jsonString,
            'headers':
                {
                    'accept': 'application/json;odata=verbose',
                    'content-type': 'application/json;odata=verbose',
                    'X-RequestDigest': jQuery('#__REQUESTDIGEST').val(),
                    "IF-MATCH": item.__metadata.etag,
                    "X-Http-Method": "MERGE"
                },
            'success': function (data) {
                var d = data;
                dfd.resolve(d);
            },
            'error': function (err) {
                dfd.reject(err);
            }
        });

        return dfd.promise();
    }
/*=====================================================
Get Item for Uploaded Document
=======================================================*/
    function getItem(file) {
        var def = jQuery.Deferred();
        jQuery.ajax({
            url: file.ListItemAllFields.__deferred.uri,
            type: "GET",
            dataType: "json",
            headers: {
                Accept: "application/json;odata=verbose"
            },
            success: function (data) {
                def.resolve(data);
            },
            error: function (data, arg, jhr) {
                def.reject(data, arg, jhr);
            }
        });
        return def.promise();
        //return call;
    }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.