Introduction
By default, client-side scripting has some restrictions while posting large sizes of data in different browsers.
While using Angular HTTP post to upload a file, I’m facing an issue -- more than a 100MB file upload breaks in some of the browsers like Chrome, Firefox, etc.
Now, I’m using file chunking to post the file as split chunks by SharePoint REST API.
Angular + SharePoint Large file upload
Follow the below-listed steps to upload the large files.
Step1
Create a "File upload" component template like below.
- <input class="upload form-control" id="DocUploader" placeholder="Upload file" type="file" (change)="UploadFile($event)">
Step2
Below is the TypeScript code for the file upload component.
- import {
- Component
- } from '@angular/core';
- @Component({
- selector: 'app-fileupload',
- templateUrl: './fileupload.component.html',
- })
- export class FileUploadComponent {
- UploadFile(event: any) {
- let fileList: FileList = event.target.files;
- if (fileList.length != 0) {
- this.fileUploadService.fileUpload(fileList[0].name, "Documents", fileList[0].name).then(addFileToFolder => {
- console.log("File Uploaded Successfully");
- }).catch(addFileToFolderError => {
- console.log(addFileToFolderError);
- });
- }
- }
- }
Step3
The important part of chunk based file upload implementation is Angular service. FileUploadService code is mentioned below.
- import {
- Injectable,
- EventEmitter
- } from '@angular/core';
- declare
- var _spPageContextInfo: any;
- declare
- var SP: any;
- @Injectable()
- export class FileUploadService {
- public siteUrl: string = _spPageContextInfo.webAbsoluteUrl;
- public siteRelativeUrl: string = _spPageContextInfo.webServerRelativeUrl != "/" ? _spPageContextInfo.webServerRelativeUrl : "";
- public fileUpload(file: any, documentLibrary: string, fileName: string) {
- return new Promise((resolve, reject) => {
- this.createDummyFile(fileName, documentLibrary).then(result => {
- let fr = new FileReader();
- let offset = 0;
-
- let total = file.size;
-
- let length = parseInt(1000000) > total ? Math.round(total * 0.8) : parseInt(1000000);
- let chunks = [];
-
- fr.readAsArrayBuffer(file);
- fr.onload = (evt: any) => {
- while (offset < total) {
-
- if (offset + length > total) {
- length = total - offset;
- }
-
- chunks.push({
- offset,
- length,
- method: this.getUploadMethod(offset, length, total)
- });
- offset += length;
- }
-
- const chunkPercentage = (total / chunks.length) / total * 100;
- if (chunks.length > 0) {
-
- const id = this.guid();
-
- this.uploadFile(evt.target.result, id, documentLibrary, fileName, chunks, 0, 0, chunkPercentage, resolve, reject);
- }
- };
- })
- });
- }
- createDummyFile(fileName, libraryName) {
- return new Promise((resolve, reject) => {
-
- var serverRelativeUrlToFolder = "decodedurl='" + this.siteRelativeUrl + "/" + libraryName + "'";
- var endpoint = this.siteUrl + "/_api/Web/GetFolderByServerRelativePath(" + serverRelativeUrlToFolder + ")/files" + "/add(overwrite=true, url='" + fileName + "')"
- const headers = {
- "accept": "application/json;odata=verbose"
- };
- this.executeAsync(endpoint, this.convertDataBinaryString(2), headers).then(file => resolve(true)).catch(err => reject(err));
- });
- }
-
- convertDataBinaryString(data) {
- let fileData = '';
- let byteArray = new Uint8Array(data);
- for (var i = 0; i < byteArray.byteLength; i++) {
- fileData += String.fromCharCode(byteArray[i]);
- }
- return fileData;
- }
- executeAsync(endPointUrl, data, requestHeaders) {
- return new Promise((resolve, reject) => {
-
- let executor = new SP.RequestExecutor(this.siteUrl);
-
- executor.executeAsync({
- url: endPointUrl,
- method: "POST",
- body: data,
- binaryStringRequestBody: true,
- headers: requestHeaders,
- success: offset => resolve(offset),
- error: err => reject(err.responseText)
- });
- });
- }
-
- uploadFileChunk(id, libraryPath, fileName, chunk, data, byteOffset) {
- return new Promise((resolve, reject) => {
- let offset = chunk.offset === 0 ? '' : ',fileOffset=' + chunk.offset;
-
- let endpoint = this.siteUrl + "/_api/web/getfilebyserverrelativeurl('" + this.siteRelativeUrl + "/" + libraryPath + "/" + fileName + "')/" + chunk.method + "(uploadId=guid'" + id + "'" + offset + ")";
- const headers = {
- "Accept": "application/json; odata=verbose",
- "Content-Type": "application/octet-stream"
- };
- this.executeAsync(endpoint, data, headers).then(offset => resolve(offset)).catch(err => reject(err));
- });
- }
-
- uploadFile(result, id, libraryPath, fileName, chunks, index, byteOffset, chunkPercentage, resolve, reject) {
-
- const data = this.convertFileToBlobChunks(result, byteOffset, chunks[index]);
-
- this.uploadFileChunk(id, libraryPath, fileName, chunks[index], data, byteOffset).then(value => {
- const isFinished = index === chunks.length - 1;
- index += 1;
- const percentageComplete = isFinished ? 100 : Math.round((index * chunkPercentage));
-
- if (index < chunks.length) {
- this.uploadFile(result, id, libraryPath, fileName, chunks, index, byteOffset, chunkPercentage, resolve, reject);
- } else {
- resolve(value);
- }
- }).catch(err => {
- console.log('Error in uploadFileChunk! ' + err);
- reject(err);
- });
- }
-
- getUploadMethod(offset, length, total) {
- if (offset + length + 1 > total) {
- return 'finishupload';
- } else if (offset === 0) {
- return 'startupload';
- } else if (offset < total) {
- return 'continueupload';
- }
- return null;
- }
-
- convertFileToBlobChunks(result, byteOffset, chunkInfo) {
- let arrayBuffer = result.slice(chunkInfo.offset, chunkInfo.offset + chunkInfo.length);
- return this.convertDataBinaryString(arrayBuffer);
- }
- guid() {
- function s4() {
- return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
- }
- return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
- }
- }
Step4
We should refer the SP.js and SP.RequestExecutor.js in deployed .aspx (or .html) pages to use default SharePoint service request executor to post file.
Output
Finally, the uploaded file will be available in SharePoint Documents Library.
References
- https://msdn.microsoft.com/en-us/library/office/dn450841.aspx#bk_FileStartUpload
- https://blogs.technet.microsoft.com/sharepointdevelopersupport/2016/11/23/always-use-file-chunking-to-upload-files-250-mb-to-sharepoint-online/
Summary
In this article, we have explored how to upload a large file in SharePoint online using Angular.