File attach (POST) to SharePoint 2013 List (custom) using Angular JS via REST API

Following describes how to upload attachment to SharePoint 2013 custom list using Angular JS.

Note: You can be consumed the JSOM libraries to achieve this, but there is limitation of 1.5 Mb. Better approach would be consuming exposed REST API (SharePoint OOTB) which allowed up to 2 Gb of file to attached using client side scripts i.e. Angular JS. .

Here I have used the “Angular File Upload” which capable of doing more tasks other than basic HTML input file control. By consuming this we can attach multiple files either to the list and etc. You can be found the information on how to include this module to your Angular view in following link.

Use package manager command to install the scripts.

For bower  -->        bower install angular-file-upload

For nugget -->       npm install angular-file-upload

It requires file buffer array to POST (save) our attachment via REST API, browsers FileReader API is required to use. Its available with almost all common browsers. You need to ensure that is available before in your environment to consume this.

HTML5 FileReader API

Its an API exposed to handle with read contents of BLOB or files. Its supported in most of the latest versions of browsers. If you further required information

View (HTML)

<div ng-app="app" ng-controller="FileUpload as vm" ng-cloak>
 <div class="row">
 <span id="btn" class="btn btn-default">Select file(s)</span>
 <!-- Example: nv-file-select="" uploader="{Object}" options="{Object}" filters="{String}" -->
 <input id="fileUploader" type="file" nv-file-select="" uploader="vm.uploader" multiple style="visibility:hidden;" />
 {{ vm.uploader.queue.length }} files attached.
 </div>
 <div class="row">
 <div uploader="vm.uploader" filters="queueLimit, customFilter">
 <table class="table">
 <tbody>
 <tr ng-repeat="item in vm.uploader.queue">
 <td wrap>{{ item.file.name }}</td>
 <td>
 <button type="button" class="btn btn-danger-focus btn-xs" ng-click="item.remove()">
 <span class="glyphicon glyphicon-trash"></span> Remove
 </button>
 </td>
 </tr>
 </tbody>
 </table>
 </div>
 </div>
</div>

 

Controller


(function () {
'use strict'

angular
.module('app')
.controller('FileUpload', ['FileUploader', 'AttachmentSvc', function (FileUploader, AttachmentSvc) {

var vm = this
, filesObj = [];

//initialization
function init() {
// Check for FileReader API (HTML5) support.
if (!window.FileReader)
console.log(&quot;[Debug] This browser does not support the FileReader API.&quot;);

vm.save = saveFile;
}
init();

//
//FILE UPLOAD
//
vm.uploader = new FileUploader({
url: ''//url for file upload
});

vm.uploader.filters.push({
name: 'customFilter',
fn: function (item /*{File|FileLikeObject}*/, options) {
//constraint for 10 files
return this.queue.length &lt; 10;
}
});

// file callbacks
vm.uploader.onAfterAddingFile = function (fileItem) {
//file added to the object array
filesObj.push(fileItem);
console.log(&quot;Files object&quot;, filesObj);
};

vm.uploader.onAfterAddingAll = function (addedFileItems) {
//console.info('onAfterAddingAll', addedFileItems);
//this will be called after adding all
//by default calls every time after file adding
};

//Code for SharePoint upload
function saveFile(event) {
event.preventDefault();
event.stopPropagation();

//get file selected
var file = filesObj[0]._file;

//convert to arraybuffer
AttachmentSvc.getFileBuffer(file)
.then(function (data) {
if (data != null)
AttachmentSvc.saveFile(data, file.name, 1);

})
.catch(function (err) {
console.log(&quot;Error on getting file array buffer&quot;)
});

}
}]);
})();

Service


(function () {

'use strict'

angular
.module('app')
.factory('AttachmentSvc', ['$q', '$resource', '$window', '$http', function ($q, $resource, $window, $http) {
var service,
ListName = 'test',
serviceId = 'AttachmentSvc';//name of document library

service = {
saveFile: saveFile,
getFileBuffer: getFileBuffer
};

//Initialization
function init() {
console.log(&quot;Initiated..&quot;, serviceId);
}
init();

return service;

//save file to custom list
function saveFile(fileArrBuffer, fileName, itemId) {
var deferred = $q.defer();
//POST request
$http({
method: 'POST',
url: spContext.webUrl + '/_api/web/lists/getbytitle(\'' + ListName + '\')/items(' + itemId + ')/AttachmentFiles/add(FileName=\'' + fileName + '\')',
headers: {
'Accept': 'application/json;odata=verbose',
'Content-Type': undefined,
'X-RequestDigest': spContext.securityValidation,//TODO: provide your digest value here,else it will throw security issues
},
data: new Uint8Array(fileArrBuffer),
transformRequest: []
}).then(function successCallback(data) {
// this callback will be called asynchronously
deferred.resolve(data);
console.log('Successfully saved.', data, serviceId, false);
}, function errorCallback(error) {
// called asynchronously if an error occurs
deferred.reject(error);
console.log('Failed to save!!!.', error, serviceId, false);
});
return deferred.promise;
}

// getting file array buffer
function getFileBuffer(file) {
var deferred = $q.defer();
var reader = new $window.FileReader();
reader.onloadend = function () {
deferred.resolve(reader.result);
}
reader.onerror = function () {
deferred.reject(reader.error);
}
reader.readAsArrayBuffer(file);
return deferred.promise;
}
}]);
})();

 

Hope this helped you! Don’t forget to share with others @kushanlahiru

References

https://msdn.microsoft.com/en-us/library/dn292553.aspx

https://msdn.microsoft.com/en-us/library/office/dn769086.aspx#UploadFile

Further references

https://msdn.microsoft.com/en-us/library/jj163201.aspx

https://msdn.microsoft.com/en-us/library/jj164022.aspx#LargeFiles

Advertisements

14 thoughts on “File attach (POST) to SharePoint 2013 List (custom) using Angular JS via REST API

  1. Hi,

    I have used above code to insert an attachment to list item, but I am getting an error message as file is not readable in getFilebuffer method.

    When I am debugging attachment has been added to list item,same is not working while not debugging.

  2. Route cause may be you not passing a valid file to to file array buffer generator. I could not mention exactly what is the issue with this statement. If you could describe more detail, I will help you out for sure.

    Thanks for sharing!

  3. Hi Kushan,

    I am using above code to save multiple attachments in to list,I am getting error message as 409 conflict error for some attachments.

    suppose I have 10 attachments to save,for 2 or 3 attachments I am getting error message 409 conflict. After spending lot of time If I call saving attachment function in attachment success then its working fine.

    For me 10 attachments is not fixed it will be dynamic, so I can’t write 10 then functions, for this I have used ajax call with async false.

    Please suggest me best approach which will increase performance.

    • Hi Bhanu,

      For first question: You may try with different file set for files which conflicting. Then also you get this issue, there may be not issue with the code may be some issue with a environment or with the code. Then there is more to work with drilling down into.

      For second question:first concern is if you use Angular then strict to its way to doing things, else maintenance issues. But with your method of doing network traffic may be higher but if your scenario facilitates large network bandwidth there wont be issue since with allowing async.

      Hope I answer you, and keep in touch for more inspirations!
      @kushanlahiru

    • I also have the same problem with multiple file attachment via loop.
      Did you find any better solution to run $http calls synchronously (or in chain) without using jQuery?

  4. Hi Kushan,

    Thank you for posting this. Quick question, can you give us an example of the url in your controller:

    vm.uploader = new FileUploader({
    url: ”//url for file upload
    });

    Please let us know.

    Thank you!

    • Thanks for motivations Jay. It was and initialization of FileUploader and does not matter whether it kept blank as for my code.

      If you not willing to consume service like in my implementation, you can be used the REST endpoint. As example as below;

      vm.uploader = new FileUploader({
      url: '/{userId}/files'
      });

      Happy for the opportunity to help you. Keep following for updated via @kushanlahiru

  5. We have tried same code but using it we are able to upload single file having size 33MB. If I try to upload file having size more than 33 MB then it is not saving in library and we getting error google chrome is running out memory while trying to display this webpage..

  6. Hi Kushan,
    Great Article. But I do not understand what is spContext.webUrl here? When I tried this code, I keep getting message as that spContext is undefined. Please, can you help, what I am missing?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s