Skip to main content

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)



[code lang="html" highlight="4" title="Angular View"]
<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>
[/code]

 

Controller



[code lang="javascript" collapse="true"]

(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;)
});

}
}]);
})();

[/code]

Service



[code lang="javascript"]

(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;
}
}]);
})();

[/code]

 
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

Comments

  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.

    ReplyDelete
  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!

    ReplyDelete
  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.

    ReplyDelete
  4. Hi There. This is a great article. But I too am having a few issues.

    Do you have a gitjhub repo I could reference please?

    ReplyDelete
  5. I have not hosted this code in a GitHub since since required to be more general. If I know your issue, then I could be able to help you! @KushanLahiru

    ReplyDelete
  6. 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

    ReplyDelete
  7. […] File attach (POST) to SharePoint 2013 List (custom) using Angular JS via REST API […]

    ReplyDelete
  8. Hi,

    I using the above code, added the js and angular reference in my file. after that I have added the HTML and js code but when I run this code in browser it gives me below errors in console , Please help.

    angular.js:38Uncaught Error: [$injector:nomod]
    angular.js:38 Uncaught Error: [$injector:modulerr]

    Please suggest, what am I doing wrong here?

    ReplyDelete
  9. Hi, I am using the above code but getting some errors. I have added the Js and angular reference and added the HTML and script code in my page but when I run this code in browser (Chrome) I am getting below errors:
    Uncaught Error: [$injector:nomod]
    Uncaught Error: [$injector:modulerr]

    please Suggest What am I doing wrong here.
    Thanks!

    ReplyDelete
  10. Hi Kaushan,

    I'm new to Angular..can you send this full solution to learn..

    ReplyDelete
  11. 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!

    ReplyDelete
  12. 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

    ReplyDelete
  13. 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..

    ReplyDelete
  14. It depends on the configuration of REST endpoint. Here I have used SharePoint and supports up to 2GB and its working fine for me.

    ReplyDelete
  15. 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?

    ReplyDelete
  16. User Angular here and no JQuery! I'm not clear where you exactly need to arrive at. @KushanLahiru

    ReplyDelete
  17. 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?

    ReplyDelete
  18. Follow and add this script. You will be find your destiny https://github.com/OfficeDev/Learning-Path-Manager-Code-Sample/blob/master/App/services/spContext.js

    ReplyDelete
  19. I have used your code for posting to folder in document library and it works !!!!

    ReplyDelete

Post a Comment

Popular posts from this blog

Turn off/ Hide Details panel/ Information Panel on modern SharePoint lists

Not always we require to show changes done by other which is a mandatory feature in SharePoint online. 
















What is details pane (aka. Information Pane)? Detail pane/ Information shows information regarding the document if you selected a one or its showing recent changes within a list or library.

Follow linkto Microsoft documentation about details pane.

Bad news: Until Microsoft listen to User Voice, there is no straightforward way to enable disable this even you don't want.
Good news: We could write a SharePoint framework extension to hack styles until Microsoft give us a permanent solution.

How? I found this sample project (Inject CSS into modern SharePoint pages with React) which could reuse to our purpose. Thanks to Hugo for saving my time.  Steps to awesomeness: Clone the projectResolve dependencies > npm iBundle > gulp bundle --shipPackage > gulp package-solution --shipUpload package into SharePoint App catalog and deploy. You could find package under SharePoint folder.A…

PowerApps Delegation warning

Warning:Delegation warning. This part "Filter" of this formula might not work correctly on large datasets. The data source might not be able to process the formula and might return an incomplete data set. Your application might not return correct results or behave correctly if the data set is incomplete
"Working with large datasets requires using data sources and formulas that can be delegated" - PowerApps 










Solution!!!500 is the default number of records to pull, but you can change this number for an entire app. 

By altering the number of delegation queries (not recommended), you will be able to pull items up to 2000 (as of 2018). 
On the File tab, select App settings.Find Experimental features, change the Data row limit for non-delegable queries setting from 1 to 2000.










Data sources that will help with delegation:Common Data Service

📢 Update -Microsoft Teams IP Phones and Intune Enrollment

For customers who require desk phones and conference room phones to make and receive audio calls or join meetings, Microsoft Teams provides a growing portfolio of devices that can be purchased from our Teams Marketplace. For Teams phones including the Yealink T56A/T58A/CP960 and the Crestron Flex series IP phones that run on Android 5.x or later, there may be specific configurations that need to be enabled in the customer's tenant for the phones to successfully enroll into Intune. Allowing successful Intune enrollment for Android versions 5.x and upIf all the following conditions below are true, you will need to enable a specific configuration setting in the Intune admin console to allow for a successful enrollment:You are deploying a Teams IP phone with Android OS version 5.x or later.You have connected your Intune tenant with managed Google Play in order to manage Android Enterprise devices.You have configured your enrollment restrictions such that Android work profile enrollmen…