Displaying uploaded files from server in dropzone js - dropzone.js

I am using the dropzone js plugin to upload files to a php server. It is working great. I am facilitating the user to update the uploaded files. So once the user clicks on update button, the dropzone appears, and I am able to display the uploaded files in it through a JQuery-AJAX call. But my problem is that though the files are displayed in the thumbnail format, the number of files in the dropzone counts to zero. I feel that the accept function is not being triggered.But if a new file is added to the displaying list the file count is 1 though there are files already existing in it.
I am using the following code to display the files in dropzone:
var mockFile = { name: "Filename", size: 12345 };
myDropzone.options.addedfile.call(myDropzone, mockFile);
myDropzone.options.thumbnail.call(myDropzone, mockFile, "/image/url");
Can anyone help me solve this?

I think you need to push the mockFile in the dropZone manually like this
myDropzone.emit("addedfile", mockFile);
myDropzone.emit("complete", mockFile);
myDropzone.files.push(mockFile);
It's work for me... if you need more code just ask!

Mock file is not uploaded as explained here https://github.com/enyo/dropzone/issues/418
If you want to submit the form use myDropzone.uploadFiles([]); in init()
$('input[type="submit"]').on("click", function (e) {
e.preventDefault();
e.stopPropagation();
var form = $(this).closest('#dropzone-form');
if (form.valid() == true) { //trigger ASP.NET MVC validation
if (myDropzone.getQueuedFiles().length > 0) {
myDropzone.processQueue();
} else {
myDropzone.uploadFiles([]);
}
}
});

example for U!
jQuery(function($) {
//文件上传
$(".dropzone").dropzone({
url : "pic_upload.jsp?id=<%=request.getParameter("id")%>",
addRemoveLinks : true,
dictRemoveLinks : "x",
dictCancelUpload : "x",
maxFiles : 5,
maxFilesize : 5,
acceptedFiles: "image/*",
init : function() {
//上传成功处理函数
this.on("success", function(file) {
alert("修改前:"+file.name);
});
this.on("removedfile", function(file) {
alert("File " + file.name + "removed");
//ajax删除数据库的文件信息
$.ajax({
type:'post',
url:'pic_delete.jsp?id='+file.name ,
cache:false,
success:function(data){
}
});
});
<%
if(null!=list){
for(PlaceImg img:list){%>
//add already store files on server
var mockFile = { name: "<%=img.getId()%>", size: <%=img.getFilesize()%> };
// Call the default addedfile event handler
this.emit("addedfile", mockFile);
// And optionally show the thumbnail of the file:
this.emit("thumbnail", mockFile, "<%=img.getImgUrl()%>");
<%}
}%>
}
});

Related

Programmatically Add Existing File to Dropzone

I'm trying to add an existing image to my dropzone programmatically, using the dropzone.js FAQ as a guide:
// Add the existing image if it's there.
// headerDropzone is my dropzone (debug shows it as existing and initialized at this point.
var on_load_header = $( '[name="on_load_header_image"]' ).val();
var on_load_header_path = $( '[name="on_load_header_image_path"]' ).val();
if ( on_load_header ) {
// Hardcoded size value is just for testing, see my second question below.
var on_load_header_data = { name: on_load_header, size: 12345 };
// Call the default addedfile event handler
headerDropzone.options.addedfile.call( headerDropzone, on_load_header_data );
// And optionally show the thumbnail of the file:
headerDropzone.options. thumbnail.call( headerDropzone, on_load_header_data, on_load_header_path);
}
My first problem is that this is just not working. The addedfile event doesn't fire (or at least the addedfile handler in headerDropzone never fires), same goes for thumbnail.
My second problem/question is: do I have to provide the file size? I could get it server side, but I'd rather not do it if I don't actually need to.
If you need to add multiple existing files into Dropzone, declare your existing files as array and then add it into Dropzone programmatically inside a loop like so...
Dropzone.autoDiscover = false;
var myDropzone = new Dropzone("#myDropzone", {
url: "/file/post",
maxFileSize: 50,
acceptedFiles: ".pdf",
addRemoveLinks: true,
//more dropzone options here
});
//Add existing files into dropzone
var existingFiles = [
{ name: "Filename 1.pdf", size: 12345678 },
{ name: "Filename 2.pdf", size: 12345678 },
{ name: "Filename 3.pdf", size: 12345678 },
{ name: "Filename 4.pdf", size: 12345678 },
{ name: "Filename 5.pdf", size: 12345678 }
];
for (i = 0; i < existingFiles.length; i++) {
myDropzone.emit("addedfile", existingFiles[i]);
//myDropzone.emit("thumbnail", existingFiles[i], "/image/url");
myDropzone.emit("complete", existingFiles[i]);
}
The Dropzone FAQ leaves out important settings required to properly preload a dropzone with (an) existing file(s).
My init method for my dropzone:
Dropzone.options.MyDropZoneID = {
...
init: function () {
var mockFile = { name: fileName, size: fileSize, type: fileMimeType, serverID: 0, accepted: true }; // use actual id server uses to identify the file (e.g. DB unique identifier)
this.emit("addedfile", mockFile);
this.createThumbnailFromUrl(mockFile, fileUrl);
this.emit("success", mockFile);
this.emit("complete", mockFile);
this.files.push(mockFile);
...
I don't know if the above is a perfect implementation, but it is working correctly with the maxFiles setting. Which is very important if you don't want buggy behavior (like the default message displaying when it shouldn't or extra files getting uploaded). You definitely need to set the accepted property to true and add the file to the files property. The only thing that I think is not required is emitting the success. I haven't played around with that enough though to know for sure.
Note: I used the following NuGet package:
Created by: Matias Meno
Id: dropzone
Version: 4.2.0
See if the functions headerDropzone.options.addedfile and headerDropzone.options.thumbnail are actually defined. It should work the way you did it, but without further info it's difficult to tell what's wrong.
About the filesize: No, it's not necessary to actually provide the accurate filesize. It's just that Dropzone automatically displays the filesize. If you don't care if some false filesize is displayed then you can just provide some random number or 0. Otherwise you might want to hide the filesize with CSS, or with JS after you add it. (The element in question has the class dz-size.
The JavaScript version of it would look something like this:
var fileSizeElement = on_load_header_data.previewElement.querySelector(".dz-size");
fileSizeElement.parentNode.removeChild(fileSizeElement);
This is now answered in official FAQ
Dropzone.options.myDropzone = {
init: function() {
let myDropzone = this;
// If you only have access to the original image sizes on your server,
// and want to resize them in the browser:
let mockFile = { name: "Filename 2", size: 12345 };
myDropzone.displayExistingFile(mockFile, "https://i.picsum.photos/id/959/600/600.jpg");
// If the thumbnail is already in the right size on your server:
let mockFile = { name: "Filename", size: 12345 };
let callback = null; // Optional callback when it's done
let crossOrigin = null; // Added to the `img` tag for crossOrigin handling
let resizeThumbnail = false; // Tells Dropzone whether it should resize the image first
myDropzone.displayExistingFile(mockFile, "https://i.picsum.photos /id/959/120/120.jpg", callback, crossOrigin, resizeThumbnail);
myDropzone.files.push(mockFile); // line missing in official docs
// If you use the maxFiles option, make sure you adjust it to the
// correct amount:
let fileCountOnServer = 2; // The number of files already uploaded
myDropzone.options.maxFiles = myDropzone.options.maxFiles - fileCountOnServer;
}
};
Originally I was doing something along these lines to programmatically upload a pre-existing file to Dropzone:
headerDropzone.emit("addedfile", imageFile);
headerDropzone.emit("thumbnail", imageFile, imageUrl);
headerDropzone.files.push(file);
However, referencing this Dropzone Github Issue I found an easier way to directly upload:
headerDropzone.uploadFiles([imageFile])
Unfortunately there are no references to this uploadFiles method in the Dropzone Documentation, so I figured I'd share some knowledge with all you Dropzone users.
Hope this helps someone
I had the same problem and found Dropzone's handleFiles(files) method.
So if you have inputTypeFileRef, you can
// inputTypeFiles.files is an object of type FileList
var fileArray = Object.values(inputTypeFiles.files || {});
myDropZone.handleFiles(fileArray);
That will also trigger all the Dropzone's events and pass file(s) data that it normally would by dragging a file on it - progress, file size, etc.
Hope it helped.
The latest Dropzone is lack of examples and the documentation is not clear or incomplete. You can use the following to add existing images to Dropzone.
for (var i = 0; i < imagesList.length; i++) {
let name = imagesList[i];
name = name.substring(name.lastIndexOf('/') + 1);
fetch(imagesList[i])
.then(res => res.blob())
.then(blob => {
let file = new File([blob], name, blob);
myDropzone1.addFile(file);
});
}
imagesList is a list of images which you want to add to Dropzone.
However, I am still facing a problem: Images are not being added or shown in the order/sequence as in imagesList. They appear rather random. Is there a way to make the images shown in the order/sequence as in imagesList?
Many of these answers are pretty dated, this is working for me in the latest Dropzone JS at the time of writing (take note of the included comments):
init: function() {
var dzObj = this;
// In my template I looped through existing files from the database and created:
// <div class="existing-image" data-url="/path/to/file.jpg"></div>
$('.existing-image').each(function() {
// I didn't have this data - works fine without
var mockFile = { name: '', size: '', dataURL: $(this).data('url') };
// Call the default addedfile event handler
dzObj.emit("addedfile", mockFile);
// The Dropzone JS FAQ incorrectly references "file" here instead of mockFile".
// The other parameters are outdated, dataURL goes in the object above,
// and you need to pass through other parameters.
// It DOES NOT WORK without the thumbnail event being triggered.
dzObj.createThumbnailFromUrl(mockFile, dzObj.options.thumbnailWidth, dzObj.options.thumbnailHeight, dzObj.options.thumbnailMethod, true, function (dataUrl) {
dzObj.emit("thumbnail", mockFile, dataUrl);
});
// Make sure that there is no progress bar, etc...
dzObj.emit("complete", mockFile);
dzObj.options.maxFiles = dzObj.options.maxFiles - 1;
});
}
#tjbp's response worked well for me, with the following changes:
I could not delete the programatically added file and then add another. I fixed this by removing this line, which was setting "maxFiles" to 0.
// If you use the maxFiles option, make sure you adjust it to the
// correct amount:
var existingFileCount = 1; // The number of files already uploaded
myDropzone.options.maxFiles = myDropzone.options.maxFiles - existingFileCount;
To make sure the "Delete" button was visible, I had to add the following line:
if (mockFile.previewElement) {
mockFile.previewElement.classList.add("dz-success");
}
Nothing here worked for me with version 5.7.0 but this did:
var myDropzone = new Dropzone(document.body, {
url: "<?= site_url('site/upload') ?>",
acceptedFiles: "<?= $uploadFieldAcceptValue ?>",
maxFilesize: 15,
maxFiles: 5,
autoQueue: false,
thumbnailWidth: 80,
thumbnailHeight: 80,
init: function(){
var that = this;
that.on("addedfile", function(file) {
// remove the start button
var startButton = file.previewElement.querySelector(".start");
if(startButton){
startButton.parentNode.removeChild(startButton);
}
});
<?php if(is_array($userUploads) && count($userUploads) > 0) { ?>
<?php foreach($userUploads as $userUpload) { ?>
<?php $file = $userUpload['file']; ?>
var mockFile = {
name: '<?= basename($file) ?>',
size: <?= filesize($file) ?>
};
var fileUrl = '<?= base_url() . str_replace('\\', '/', preg_replace('~^'. preg_quote(FCPATH) .'~', '', $file)) ?>';
var callback = null;
var crossOrigin = null;
var resizeThumbnail = true;
that.displayExistingFile(mockFile, fileUrl, callback, crossOrigin, resizeThumbnail);
that.emit("success", mockFile);
that.emit('complete', mockFile);
<?php } ?>
that.options.maxFiles = that.options.maxFiles - <?= count($userUploads) ?>;
<?php } ?>
}
});
On Dropzone 5.7.0 there is a "displayExistingFile" function. I called it on init section, works fine.
/**
* Called when dropzone initialized
* You can add event listeners here
*/
init: function init() {
var mockFile = { name: "Filename 1.pdf", size: 12345678 };
this.displayExistingFile(mockFile, "../../assets/site/wp-content/uploads/cropped-ic_credifisco-1-192x192.png");
},

Looking for a good example on File upload with asp.net mvc3 & knockout.js

I am trying to look for a good comprehensive example of multiple file upload with asp.net mvc3 & knockout.js. I been looking around but nothing that shows the solution from start to finish! There examples that show what the knockout binding needs to be, but doesn't show how to read the files in the "Controller". Goal is upload and save files to db. Example of saving to a AWS S3 storage is a plus. Please help.
ko binding:
<input type="file" data-bind="value: fileToUpload, fileUpload: fileToUpload, url : 'Client/Upload' " />
ko.bindingHandlers.fileUpload = {
update: function (element, valueAccessor, allBindingsAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor())
if (element.files.length && value) {
var file = element.files[0];
var url = allBindingsAccessor().url
xhr = new XMLHttpRequest();
xhr.open("post", url, true);
xhr.setRequestHeader("Content-Type", "image/jpeg");
xhr.setRequestHeader("X-File-Name", file.name);
xhr.setRequestHeader("X-File-Size", file.size);
xhr.setRequestHeader("X-File-Type", file.type);
console.log("sending")
// Send the file (doh)
xhr.send(file);
}
}
}
[HttpPost]
public ActionResult Upload()
{
//Not sure what to do here.
}
Also need to do multiple file upload? Not sure how to set the viewmodels.
On the javascript side I would suggest using fineuploader http://fineuploader.com/. you can create a custom binding for updating the viewmodel with the response.
<div data-bind="fileupload: viewModel.fileName"></div>
ko.bindingHandlers.fileUpload = {
init: function (element, valueAccessor) {
var $element = $(element);
var fileNameVal = valueAccessor;
var uploader = new qq.FineUploader({
element: $element[0],
request: {
endpoint: 'server/your_upload_service'
},
multiple: true,
validation: {
allowedExtensions: ['jpeg', 'jpg', 'txt']
},
callbacks: {
onComplete: function(id, fileName, responseJSON) {
if (responseJSON.success) {
// update your value
valueAccessor(fileName)
//may need to change this if you pass a reference back
// in your responseJSON such as an s3 key
}
}
}
});
}
};
as for the server side I am not familiar with ASP.net but you should be able to interact with the request data on your endpoint and extract the multipart encoded form parts that contain the image data.
might want to look at these answers
MVC 3 file upload and model binding
File Upload ASP.NET MVC 3.0
also note that fineuploader sends the file in the request with the key "qqfile"

dilemna with jqgrid and ajaxfileupload

I am using jqgrid and ajaxFileUpload.js script in order to pass parameters and files to a php script. The structure of the code is like this:
...
url:url_1.php,
beforeSubmit: function (postdata,formid)
{
$.ajaxFileUpload (
{
url: url_2.php,
...
success:
error:
}),
return[true,""];
},
afterSubmit: function(reponse,postdata)
{
...
return [true,'',''];
}
I have a dilemna:
According to the jqgrid behaviour, url_2.php is called, then url_1.php.
url_2.php handles the data (parameters + file), url_1.php handles nothing.
url_2.php could return an error or message (e.g "already exist") but, the errors are displayed in the form by the aftersubmit event, and this event receives error from url_1.php !!!
I suppose that I am obliged to put the ajaxfileupload in the beforesubmit event !!!
Any ideas to solve this dilemna ?
You can use jquery form plugin and jqGrid dataProxy method instead.
useDataProxy: true,
dataProxy : function (opts, act) {
opts.iframe = true;
var $form = $('#FrmGrid_' + $grid.jqGrid('getGridParam', 'id'));
//Prevent non-file inputs double serialization
var ele = $form.find('INPUT,TEXTAREA,SELECT').not(':file');
ele.each(function () {
$(this).data('name', $(this).attr('name'));
$(this).removeAttr('name');
});
//Send only previously generated data + files
$form.ajaxSubmit(opts);
//Set names back after form being submitted
setTimeout(function () {
ele.each(function () {
$(this).attr('name', $(this).data('name'));
});
}, 200);
};
For example http://jqgrid-php.net file fileUpload class uses this. This is described in How to force dataProxy call in form editing if editurl is set in jqgrid also.

AntiForgeryToken not being received when using plupload in form submission

I'm using Plupload to allow multiple images to be uploaded to an mvc3 web app.
the files upload OK, but when i introduce the AntiForgeryToken it doesn't work, and the error is that no token was supplied, or it was invalid.
I also cannot get the Id parameter to be accepted as an action parameter either, it always sends null. So have to extract it myself from the Request.UrlReferrer property manually.
I figure plupload is submitting each file within the upload manually and forging its own form post.
My form....
#using (#Html.BeginForm("Upload", "Photo", new { Model.Id }, FormMethod.Post, new { id = "formUpload", enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.HiddenFor(m => m.Id)
<div id="uploader">
<p>You browser doesn't have HTML5, Flash or basic file upload support, so you wont be able to upload any photos - sorry.</p>
</div>
<p id="status"></p>
}
and the code that wires it up...
$(document).ready(function ()
{
$("#uploader").plupload({
// General settings
runtimes: 'html5,flash,html4',
url: '/Photo/Upload/',
max_file_size: '8mb',
// chunk_size: '1mb',
unique_names: true,
// Resize images on clientside if we can
resize: { width: 400, quality: 100 },
// Specify what files to browse for
filters: [
{ title: "Image files", extensions: "jpg,gif,png" }
],
// Flash settings
flash_swf_url: 'Content/plugins/plupload/js/plupload.flash.swf'
});
$("#uploader").bind('Error', function(up, err)
{
$('#status').append("<b>Error: " + err.code + ", Message: " + err.message + (err.file ? ", File: " + err.file.name : "") + "</b>");
});
// Client side form validation
$('uploadForm').submit(function (e)
{
var uploader = $('#uploader').pluploadQueue();
// Validate number of uploaded files
if (uploader.total.uploaded == 0)
{
// Files in queue upload them first
if (uploader.files.length > 0)
{
// When all files are uploaded submit form
uploader.bind('UploadProgress', function ()
{
if (uploader.total.uploaded == uploader.files.length)
$('form').submit();
});
uploader.start();
} else
alert('You must at least upload one file.');
e.preventDefault();
}
});
});
and here is the controller action that receives it...
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Upload(int? id, HttpPostedFileBase file)
{
if (file.ContentLength > 0)
{
var parts = Request.UrlReferrer.AbsolutePath.Split('/');
var theId = parts[parts.Length - 1];
var fileName = theId + "_" + Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
file.SaveAs(path);
}
return Content("Success", "text/plain");
}
As you can see, i have had to make the id parameter nullable, and i extract this manually in the action method.
How can i ensure that the values are sent with each form post correctly?
short answer : YES!
use multipart_params options like this:
multipart_params:
{
__RequestVerificationToken: $("#modal-dialog input[name=__RequestVerificationToken]").val()
}
short answer: you can't.
What you can do in this case is pass your token either as another multipart paramenter (if using that), or as part of the URL as a GET parameter, but nothing from the form will be sent by plupload as it builds its own request.
Another possibility is using custom headers to pass back the token to the server (plupload has a headers option), but whichever is the method you use, you will have to process it on your backend to validate it.

Ajax Upload using valums ajax upload plugin inside a form

i just came across this ajax upload plugin and i wish to use it inside a form as shown in the demo page example 3. For some reason i am not able to make it work. I am not sure what parameters come into the function. For example here is my sample code.
$(document).ready(function(){
var upload = new AjaxUpload('property_i',
{
action: 'submitproperty.php',
autoSubmit: false,
onSubmit : function(file , extension){
return false;
}
});
var upload_data = upload.setData({
'propertytype':'propertytype'
});
});
Now the ID used in the AjaxUpload function should be ID of the or of the Entire form. Also how do i use setData method. Any suggestions or links will be very helpful. Thanks
I got it to work with the following code:
new AjaxUpload('#uploader_button', {
action: 'filename.ashx',
autoSubmit: true,
onSubmit: function(file, ext) {
// --- stuff here
// --- add postdata parameters
this.setData({ id: 1, title: docTitle.val() });
},
onComplete: function(file, response) {
// --- stuff here too
}
});
it doesn't utilize the var but instead adds the custom data params in the onSubmit block. The only other difference is that I haven't wrapped the parameter key in quotes as it seems to serialize correctly. And I'm not using autoSubmit: false , but instead it's true...
The only way I could get this to work with autoSubmit: false is to add this outside any function:
var uploader;
var uploadFile;
then in the AjaxUpload(...
onChange: function(file, response){
uploader = this;
uploadFile = file;
},
then in the function to do the upload:
uploader.setData({session: session});
uploader.submit();
Hope this helps
I'm using uploadify and very useful.
http://www.uploadify.com/

Resources