Skip to content

Instantly share code, notes, and snippets.

@dmitryevseev
Created January 13, 2014 11:38
Show Gist options
  • Save dmitryevseev/8398865 to your computer and use it in GitHub Desktop.
Save dmitryevseev/8398865 to your computer and use it in GitHub Desktop.
File upload with drag&drop and FormData
<label id="image_container">Upload image:
<div id="image_dropzone"
class="dropzone"
dropzone="copy file:image/png file:image/gif file:image/jpeg file:image/jpg file:image/jpe file:image/ico file:image/icon file:text/ico file:application/ico file:image/x-icon file:image/tiff file:image/tif file:image/x-windows-bmp file:image/bmp">
<h3>Click to select image files<br>or just drop files here</h3>
<input type="file" id="image_fileInput" name="UploadForm[image]">
</div>
</label>
/**
* IMAGE UPLOAD CODE
* ============================================= */
/**
* dragenter event handler
* @param event {object}
*/
var containerDragenter = function (event) {
if (event.target === $scope.container) {
angular.element($scope.dropzone).addClass('dragstarted');
}
};
/**
* dragleave event handler
* @param event
*/
var containerDragleave = function (event) {
if (event.target === $scope.container) {
angular.element($scope.dropzone).removeClass('dragstarted');
}
};
/**
* event listener fired on files selected/dropped
* @param event {object}
*/
$scope.images = [];
var images = $scope.images;
var handleDrop = function (event) {
event.stopPropagation();
var files = event.target.files;
angular.element($scope.dropzone).addClass("processing");
// handle the last one file
var i = files.length - 1;
//init empty object (status: new, uploading, error, done )
images.push({ file: files[i], status: 'new', percentage: 0, fieldIndex: $scope.activeFieldIndex });
// iterate over file(s) and process them for uploading
uploadFile(images.length - 1);
angular.element($scope.dropzone).removeClass("processing");
};
/**
* helper function to create new instance of FileReader
*/
$scope.createFileReader = function () {
return new FileReader();
};
//upload events listeners
var uploadProgress = function (event, fileIndex) {
$scope.$apply(function () {
var image = images[fileIndex];
image.status = 'uploading';
image.percentage = Math.round((event.loaded / event.total) * 100);
});
};
var uploadError = function (event, fileIndex) {
$scope.$apply(function () {
images[fileIndex].status = 'error';
});
};
var uploadAbort = function (event, fileIndex) {
//
};
var uploadComplete = function (event, fileIndex) {
$scope.$apply(function () {
var image = images[fileIndex];
if (image.status !== 'error') {
image.percentage = 100;
image.status = 'done';
}
});
};
/**
* performs file upload to api
* @param fileIndex {int} index of file object in images array
*/
var uploadFile = function (fileIndex) {
var image = images[fileIndex],
fd = new FormData();
//fd.append('file', image.file);//upload original file
fd.append('image', image.file);
image.xhr = new XMLHttpRequest();
//register upload progress event listener
image.xhr.upload.addEventListener("progress", function (event) {
uploadProgress(event, fileIndex);
}, false);
image.xhr.addEventListener("load", function (event) {
uploadComplete(event, fileIndex);
}, false);
image.xhr.addEventListener("error", function (event) {
uploadError(event, fileIndex);
}, false);
image.xhr.addEventListener("abort", function (event) {
uploadAbort(event, fileIndex);
}, false);
image.xhr.onload = function (event) {
if (this.status == 200) {
//image successfully uploaded - populate object with received data
var apiResponse = JSON.parse(this.responseText);
$scope.$apply(function () {
var image = images[fileIndex];
image.url = apiResponse.response.image;
$scope.form.fields[image.fieldIndex].value = image.url;
if (apiResponse.response.width > 800) {
var proportion = 800 / apiResponse.response.width;
apiResponse.response.width = 800;
apiResponse.response.height = Math.ceil(proportion * apiResponse.response.height);
}
// update image dimentions with actual
$scope.form.fields[image.fieldIndex].settings.width = apiResponse.response.width;
$scope.form.fields[image.fieldIndex].settings.height = apiResponse.response.height;
});
} else {
//some error occurred
apiResponse = JSON.parse(this.responseText);
if (apiResponse.status === false) {
$scope.$apply(function () {
image = images[fileIndex];
image.status = 'error';
});
}
}
};
//send file to server
image.xhr.open("POST", '/location/' + $scope.form.location_id + '/manage/uploadImage');
image.xhr.send(fd);
};
// init html elements event listeners
var ctrlPrefix = 'image_';
if (!$scope.dropzone) {
$scope.dropzone = document.getElementById(ctrlPrefix + 'dropzone');
}
if (!$scope.fileInput) {
$scope.fileInput = document.getElementById(ctrlPrefix + 'fileInput');
}
if (!$scope.container) {
$scope.container = document.getElementById(ctrlPrefix + 'container');
}
if (!$scope.container) {
throw 'Error: no container element found (#' + ctrlPrefix + 'container)';
}
if (!$scope.fileInput) {
throw 'Error: no input[type="file"] found (#' + ctrlPrefix + 'fileInput)';
}
$scope.fileInput.addEventListener("change", handleDrop, false);
$scope.container.addEventListener('dragenter', containerDragenter, true);
$scope.container.addEventListener('dragleave', containerDragleave, true);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment