DropZone.js determine when successful upload - javascript

I am using Dropzone.js to upload an Excel file, of which it's contents is then imported to a table in my database.
I currently have methods in my c# which check the file being uploaded, to make sure it is valid (checks header row) and can be imported to the database.
The validation works fine, as does DropZone.js in theory. However, no matter if the file passes validation and is imported, or not, DropZone will always show the 'tick/check' mark - to notify the user that the action has completed successfully.
Here is my Dropzone:
Dropzone.options.forecastDropzone = {
init: function () {
thisDropzone = this;
this.on("success", function (file, Message) {
console.log(Message.Message)
toastr.info(Message.Message, {
timeOut: 0, tapToDismiss: true, preventDuplicates: true
});
});
},
};
HTML:
<form action="/Power/Upload" class="dropzone" id="forecastDropzone"></form>
And the 'Upload' method which is being called:
[HttpPost]
public ActionResult Upload()
{
string filename = "";
string path = "";
try
{
foreach (string fileName in Request.Files)
{
HttpPostedFileBase file = Request.Files[fileName];
path = AppDomain.CurrentDomain.BaseDirectory + "Uploads/";
filename = Path.GetFileName(Request.Files[fileName].FileName);
Request.Files[fileName].SaveAs(Path.Combine(path, filename));
ValidateExcel(path, filename);
}
}
catch
{
isSavedSuccessfully = false;
}
return Json(isSavedSuccessfully == true ? new { Message = "Successfully Saved!" } : new { Message = "Error in saving file" });
}
So the Upload method is returning a JSON object. And I want DropZone to determine whether the save/import was successful, based on a value from the JSON. Is this possible?
Many thanks

Instead of trying to parse the JSON response and handle the error client side, I would make your server responsible for this.
Specifically: have your server return something other than a successful HTTP 200 response when an upload fails. DropZone will treat an upload as failed if it receives a 4xx or 5xx response from the server.

Related

Dropzonejs trigger error and cancel upload

i'm using Dropzonejs and what I would like to do is essentially simple. But I can't find any article about it.
So on sending the file we trigger an error on nasty .exe and .php files. The dropzonejs interface show an X and and error message. So that's correct. The problem is that it still gets thrown into the on success event, and gets uploaded.
uploader.on("sending", function (file, xhr, data) {
var aDeny = [ // deny file some extensions by default
'application/x-msdownload',
'text/php'
];
if($.inArray(file.type, aDeny) !== -1) {
this.defaultOptions.error(file, 'File not allowed: ' + file.name);
return false;
}
});
Evil.exe still appears in this success event and gets uploaded. The response only has a string of the file path and file.status is success.
uploader.on('success', function (file, response) {
getData({'dostuff'});
return file.previewElement.classList.add("dz-success");
});
So in my 'sending' event, how can I prevent the file from appearing in the success event?
UPDATE:
Thanks! This is what I needed in the end:
var aDeny = [ // deny file some extensions by default
'application/x-msdownload',
'text/php'
];
Dropzone.options.uploadWidget = {
// more config...
accept: function (file, done) {
if ($.inArray(file.type, aDeny) !== -1) {
done("This file is not accepted!");
}
else {
done();
}
}
}
I would first of all always check the file type on the server side to prevent any problems.
Then to filter file types with Dropzone you can use:
acceptedFiles option
The default implementation of accept checks the file's mime type or
extension against this list. This is a comma separated list of mime
types or file extensions.
Eg.: image/*,application/pdf,.psd
If the Dropzone is clickable this option will also be used as accept
parameter on the hidden file input as well.
Sample:
var myDropzone = new Dropzone("div#myId", {
url: "/file/post",
acceptedFiles: 'application/x-msdownload,text/php'
});
accept function
A function that gets a file and a done function as parameters.
If the done function is invoked without arguments, the file is
"accepted" and will be processed. If you pass an error message, the
file is rejected, and the error message will be displayed. This
function will not be called if the file is too big or doesn't match
the mime types.
Sample:
Dropzone.options.myAwesomeDropzone = {
paramName: "file", // The name that will be used to transfer the file
maxFilesize: 2, // MB
accept: function(file, done) {
if (file.name == "justinbieber.jpg") {
done("This file is not accepted!");
}
else { done(); }
}
};

Response for FileUploader's uploadComplete-Event is undefined

I'm developing a SAPUI5 app and use the FileUploader control in my app to upload documents to a server. The uploading works and I also receive a response from the server (I can see this in the DevTools of Chrome).The problem is that the event-object inside the 'uploadComplete' event-handler always returns undefined for the response parameter.
Do you know why this is the case and how I can fix it?
Here is the initialization of the FileUploader:
var oFileUploader = new sap.ui.unified.FileUploader({
uploadUrl: "/fileupload",
name: "documentUploader",
uploadOnChange: false,
multiple: false,
width: "400px",
uploadComplete: this.onDocumentUploadComplete
});
And here is the 'uploadComplete' event-handler:
onDocumentUploadComplete: function(oEvent) {
var response = oEvent.getParameter("response");
console.log(response); // response = undefined
}
I still haven't figured out how to receive the server's response but I have found a workaround.After uploading the file I just send a request to the server and tell it to check whether the file exists.If it exists the server returns "true" and if it doesn't the server returns "false". Here's my code:
// eventhandler for the "uploadComplete"-event of the FileUploader-control
onDocumentUploadComplete: function(oEvent) {
var uploaderControl = oEvent.getSource();
var documentname = uploaderControl.getValue();
var fileURI = "/file/" + documentname + "?exists";
$.get(fileURI, function(data) {
if (data === "true") {
console.log("Successfully uploaded: " + documentname);
this.handleDocumentUploadSuccess(documentname);
} else {
console.log("Error when uploading document: " + documentname);
this.handleDocumentUploadError(documentname);
}
}.bind(this));
}
According to the documentation the parameter response is subject to some conditions.
Response message which comes from the server. On the server side this
response has to be put within the "body" tags of the response document
of the iFrame. It can consist of a return code and an optional
message. This does not work in cross-domain scenarios.
That means the response fom the server must be XML or HTML.

Blueimp jQuery File Upload and my exception

I want to pass error message to Blueimp jQuery File Upload plugin. I use ASP.NET MVC and throw my own exception when some conditions are appeared (i.e. file is not real image, only image exception or image is too wide etc).
var file = Request.Files[i];
_service.ImageValidation(file.InputStream);
public void ImageValidation(System.IO.Stream fileStream)
{
Bitmap bmp = null;
try
{
bmp = new Bitmap(fileStream, false);
}
catch
{
throw new NoImageException();
}
if (bmp.Width > bmp.Height && (bmp.Width < 1024 || bmp.Height < 768))
throw new ImageDimensionTooSmall();
if ((bmp.Width <= bmp.Height) && (bmp.Width < 768 || bmp.Height < 1024))
throw new ImageDimensionTooSmall();
fileStream.Position = 0;
}
on client side I try to catch error by the following way:
$('#fileupload').fileupload({
url: '/SmartphonePhotographer/ManageFiles?ResponseID=' + ResponseID,
error: function (e, data) {
alert('error');
}
});
'data' variable always has 'error' value. 'e' has many properties, including statusText='Internal server error' and responseText (html page with exception). Question - how can I pass error message on server side to catch it on client side (maybe, there is an json format for errors, but I did not find it in documentation)
It goes to the error event because you are throwing an exception in your server side code. So the ajax call is getting a 500 internal error response.
What you can do is, instead of throwing an exception, return a json response with the error messages.
[HttpPost]
public ActionResult SaveImage()
{
if(IsFileNotValid()) //your method to validate the file
{
var customErrors = new List<string> {"File format is not good",
"File size is too bib"};
return Json(new { Status = "error", Errors = customErrors });
}
//Save/Process the image
return Json ( new { Status="success", Message="Uploaded successfully" });
}
And in the done() event, you can inspect the json response and show the error messages as needed.
$('#fileupload').fileupload({
url: '/SmartphonePhotographer/ManageFiles?ResponseID=' + ResponseID,
error: function (e, data,txt) {
alert('error' + txt);
}
}).done(function(response){
if(response.Status==="error")
{
$.each(services.Errors, function (a, b) {
alert(b);
});
}
});
With this approach, you can send multiple validation errors back to the client and client can process(show to user ?) it.
MVC 6
In MVC6, you can return an HttpStatusCode response directly from the MVC controller action. So no need to send a JSON response yourself.
[HttpPost]
public IActionResult SaveImage()
{
var customErrors = new List<string> { "File format is not good",
"File size is too bib" };
return HttpBadRequest(customErrors);
}
This will send a 400 Response to the caller with the data we passed(the list of errors) in the response. So you can access the responseJSON property of your error xHr object of the error event to get it
error: function (a, b, c) {
$.each(a.responseJSON, function (a, b) {
alert(b);
});
}
I agree your issue is that you are throwing an exception versus returning a controlled response. Most frameworks look for status codes in the 400x or 500x. So you want to return a friendly json object and a status code in those ranges. If you do that your data object in the error block will be what you returned.
MVC Land:
//get a reference to request and use the below.
return this.Request.CreateResponse(HttpStatusCode.BadRequest, "Your message here");
Web Api 2
Use an IHttpActionResult and return BadRequest("My error message"); If you do that it will set your status code and return the response as the data.

Valums FileUploader no response from server after upload

I am using Valums FileUploader and I am having trouble getting and reading a response after a file is uploaded. Basically I am trying to get a useful response to be used in onComplete, whether that be success or an error message.
I found another post here that said perhaps the server needs to be set to content-type plain/text. I checked that, and indeed that is the setting.
Anyway, been doing a lot of searching and finding various things to check, but nothing yet seems to solve my problem.
Here is some abbreviated code from the uploader:
var uploader = new qq.FileUploaderBasic({
button: document.getElementById('btnUpChange'),
action: templateURL+'/upload.php',
allowedExtensions: ['jpg', 'jpeg', 'png', 'gif'],
onSubmit: function(id, fileName) {
},
onComplete: function(id, fileName, responseJSON) {
var fileMsg = responseJSON;
console.log(fileMsg);
$('#filemsg').html('<span class="red" >'+fileMsg+'</span>');
}
});
And here is the text from the console after upload:
"[uploader] xhr - server response received"
"[uploader] responseText = File is too large"
[object Object]
I intentionally set the $sizeLimit small to throw an error just to try and get a message.
I took the php.php file included in the uploader zip, copied and renamed it, then added at the end this:
$allowedExtensions = array('jpg', 'jpeg', 'png', 'gif');
$sizeLimit = 4 * 1024;
$uploader = new qqFileUploader($allowedExtensions, $sizeLimit);
// Call handleUpload() with the name of the folder, relative to PHP's getcwd()
$result = $uploader->handleUpload('uploads/', $replaceOldFile = true);
if ($result['success'] !== true) {
echo $result['error'];
} else {
echo $result['success'];
}
If the upload is successful, I just get a 1 returned to the onComplete method. I tried to use responseJSON.responseText and all I got was "undefined".
Thank you for your help.
Found the solution to this...
First, on the php.php I put at the end this code:
echo htmlspecialchars(json_encode($result), ENT_NOQUOTES);
Then, in the onComplete function the JSON response can be returned like this:
onComplete: function(id, fileName, responseJSON) {
var newFile = responseJSON.filename;
var theError = responseJSON.error;
}
where the key name from the response array created in the php.php can be anything you want and is returned as in the example like this: responseJSON.keyname

DropZone.js server side validation

I'm doing server side validation for the files uploaded. Not every file that makes it to the server is stored. How can I display/trigger the error on the file(s) that were not successfully stored on the server. I've tried adding a server Validation function but can't figure out how to do it... Please help
this.on("successmultiple", function (file, successResponse) {
uploadResult = eval(successResponse);
toastr.options.positionClass = "toast-bottom-right";
var ErrorMessage = "";
for (var i = 0; i < uploadResult.ResultList.length; i++) {
var result = uploadResult.ResultList[i];
if (result.IsSuccessful === "True") {
toastr.success(result.Message);
if (hdnFileIDList !== "")
hdnFileIDList = hdnFileIDList + "|" + result.ID;
else
hdnFileIDList = result.ID
}
else {
//-- trigger dropzone error
toastr.warning(result.Message);
//this.ValidationError(file, result.Message);
file.accepted = false;
file.status = Dropzone.ERROR;
dropzone.serverError(file, result.Message);
//dropzone.emit("errormultiple", file, result.Message);
}
}
$("#<%=hdnSharedFileObjNewFileIDList.clientID%>").val(hdnFileIDList);
});
Solved my problem by adding the following code to Dropzone.js then calling it from my "successmultiple" event when I see and error in my returned JSON from the server.
Dropzone.prototype.serverError = function (file, message) {
file.accepted = false;
file.status = Dropzone.ERROR;
return this._errorProcessing(file, message);
};
To anyone else that's landed here after searching for a solution to this problem: there's a pretty simple and elegant way to deal with this without getting into the guts of Dropzone. If your server side validation fails, return a status code of 400 (bad request) and include your error message as a jsonResponse.
Then you can handle the response with something like the following code in your dropzone's init configuration (assuming you are sending your error message as "ValidationMessage"):
this.on("error", function (file, jsonResponse) {
var errorMessage = "Could not upload document: ";
if (jsonResponse["ValidationMessage"] != null) {
errorMessage += jsonResponse["ValidationMessage"];
} else {
errorMessage += "unknown error";
}
alert(errorMessage);
});
The file will have a big red X on it just like a regular Dropzone failed upload.
This solution is for single uploads rather than multiple but the same idea should work for multiple.

Categories