I try to use JQueryFileUpload plugin to make ajax upload while form filling. But I have hard issue because I need to have different url to those in form params.
I use url param in JQueryFileUpload object but it doesnt works well if file input field is located in form. Then it uses form action url 'index.php?option=com_xxx&layout=edit&id=0' in .fileupload function instead of this url 'index.php?option=com_xxx&task=item.uploadImage'.
How to use ulr param in fileupload function and have file field inside some form with different action url? Is it possible?
JQuery code:
jQuery('#jform_file').fileupload({
url: 'index.php?option=com_xxx&task=item.uploadImage',
// This element will accept file drag/drop uploading
dropZone: jQuery('#drop'),
// This function is called when a file is added to the queue;
// either via the browse button, or via drag/drop:
add: function (e, data) {
var tpl = jQuery('<li class="working"><input type="text" value="0" data-width="48" data-height="48"'+
' data-fgColor="#0788a5" data-readOnly="1" data-bgColor="#3e4043" /><p></p><span></span></li>');
// Append the file name and file size
tpl.find('p').text(data.files[0].name)
.append('<i>' + formatFileSize(data.files[0].size) + '</i>');
// Add the HTML to the UL element
data.context = tpl.appendTo(ul);
previewImage(data);
// Initialize the knob plugin
tpl.find('input').knob();
// Listen for clicks on the cancel icon
tpl.find('span').click(function(){
if(tpl.hasClass('working')){
jqXHR.abort();
}
tpl.fadeOut(function(){
tpl.remove();
});
});
// Automatically upload the file once it is added to the queue
var jqXHR = data.submit();
},
progress: function(e, data){
// Calculate the completion percentage of the upload
var progress = parseInt(data.loaded / data.total * 100, 10);
// Update the hidden input field and trigger a change
// so that the jQuery knob plugin knows to update the dial
data.context.find('input').val(progress).change();
if(progress == 100){
data.context.removeClass('working');
}
},
fail:function(e, data){
// Something has gone wrong!
data.context.addClass('error');
}
});
Form html:
<form action="index.php?option=com_xxx&layout=edit&id=0" method="post" name="adminForm" id="adminForm" class="form-validate">
<input type="file" name="jform[file]" id="jform_file" />
</form>
By accident I found out the solution. I added one more fileupload call before the right one:
jQuery(function(){
jQuery('#adminForm').fileupload();
jQuery('#jform_file').fileupload({
url: 'index.php?option=com_xxx&task=item.uploadImage',
});
});
First one return form action url result so it can cause some issues. But second call returns result from url param.
Related
In routes.php I have the following routes:
Route::post('dropzone', ['as' => 'dropzone.upload', 'uses' => 'AdminPhotoController#dropzoneUpload']);
Route::post('dropzone/delete', ['as' => 'dropzone.delete', 'uses' => 'AdminPhotoController#dropzoneDelete']);
In AdminPhotoController.php I did in the following way:
public function dropzoneUpload(Request $request)
{
if($request->ajax()) { // hmm, do I really need this?
if ($request->hasFile('file') && $request->file('file')->isValid()) {
$image_file = $request->file('file');
$image_name = time() . '_' . $image_file->getClientOriginalName();
$destinationPath = 'images/photos';
if ($image_file->move($destinationPath, $image_name)) {
$photo = new Photo(['file_name' => $image_name, 'title' => 'No title', 'description' => 'No description']);
\Auth::user()->photos()->save($photo);
return \Response::json('success', 200);
} else {
return \Response::json('error', 400);
}
}
}
}
Finally, here are my HTML & JS:
<div class="dropzone" id="dropzoneFileUpload">
</div>
<script type="text/javascript">
Dropzone.autoDiscover = false; // to disable the auto discover behaviour of Dropzone (sami ga definisemo ispod)
var myDropzone = new Dropzone("div#dropzoneFileUpload", {
url: "{{ route('dropzone.upload') }}",
headers: {
'X-CSRF-TOKEN': '{!! csrf_token() !!}'
}
});
</script>
And it works, uploading files works. But I would like to have the remove links for deleting uploaded images. I was reading the official documentation on http://www.dropzonejs.com/ but I still don't understand how to do it. I see that there are:
removedfile event - Called whenever a file is removed from the list. You can listen to this and delete the file from your server if you want to;
and .removeFile(file) method - If you want to remove an added file from the dropzone, you can call .removeFile(file). This method also triggers the removedfile event.
So I started like this but I don't know how to do it, how to delete those images:
Dropzone.options.dropzoneFileUpload = { // div has id=dropzoneFileUpload?
addRemoveLinks: true, // but still link to delete is not displayed?
dictRemoveFile: 'Remove'
};
myDropzone.on("complete", function(file) {
myDropzone.removeFile(file); // What should I do here?
});
.
EDIT:
If I remove this code:
Dropzone.autoDiscover = false;
var myDropzone = new Dropzone("#my-dropzone", {
url: "{{ route('dropzone.upload') }}",
headers: {
'X-CSRF-TOKEN': '{!! csrf_token() !!}'
}
});
solution that that #Manuel Azar gave will work, Remove Links are now displayed (for each uploaded image). So, there is some problem with this code, something is missing.
Take a look at this answer to help you understand the dropzone events:
https://stackoverflow.com/a/19454507/4734404
Then you should add an action to your controller for your delete request to remove the image from DB and disk:
public function dropzoneRemove(Request $request)
{
if($request->ajax()) {
$photo = Photo::find($request->photoId); //Get image by id or desired parameters
if(File::exists($destinationPath.$photo->file_name)) //Check if file exists
File::delete($destinationPath.$photo->file_name) //Delete file from storage
$photo->delete() //Delete file record from DB
return response('Photo deleted', 200); //return success
}
}
I would recommend you to take a look at laravel's Storage facade, to keep your files well organized in your filesystem.
https://laravel.com/docs/5.2/filesystem
EDIT:
How to add a button to remove each file preview?
Starting with Dropzone version 3.5.0, there is an option that will handle all this for you: addRemoveLinks. This will add an Remove file element to the file preview that will remove the file, and it will change to Cancel upload if the file is currently being uploaded (this will trigger a confirmation dialog).
You can change those sentences with the dictRemoveFile, dictCancelUpload and dictCancelUploadConfirmation options.
If you still want to create the button yourself, you can do so like this:
<form action="/target-url" id="my-dropzone" class="dropzone"></form>
<script>
// myDropzone is the configuration for the element that has an id attribute
// with the value my-dropzone (or myDropzone)
Dropzone.options.myDropzone = {
init: function() {
this.on("addedfile", function(file) {
// Create the remove button
var removeButton = Dropzone.createElement("<button>Remove file</button>");
// Capture the Dropzone instance as closure.
var _this = this;
// Listen to the click event
removeButton.addEventListener("click", function(e) {
// Make sure the button click doesn't submit the form:
e.preventDefault();
e.stopPropagation();
// Remove the file preview.
_this.removeFile(file);
// If you want to the delete the file on the server as well,
// you can do the AJAX request here.
});
// Add the button to the file preview element.
file.previewElement.appendChild(removeButton);
});
}
};
</script>
From FAQ: https://github.com/enyo/dropzone/wiki/FAQ#how-to-add-a-button-to-remove-each-file-preview
More info here about customizing dropzone properties: http://www.dropzonejs.com/#layout
EDIT 2
The problem is here:
Dropzone will find all form elements with the class dropzone, automatically attach itself to it, and upload files dropped into it to the specified action attribute. http://www.dropzonejs.com/#usage
Alternatively you can create dropzones programmaticaly (even on non form elements) by instantiating the Dropzone class http://www.dropzonejs.com/#create-dropzones-programmatically
Dropzone.autoDiscover = false; // to disable the auto discover behaviour of Dropzone (sami ga definisemo ispod)
var myDropzone = new Dropzone("div#dropzoneFileUpload", {
I believe you have two instances of Dropzone because you are creating another Dropzone object. You should stick to the quick config and edit the options directly, and remove autoDiscover = false, instead of doing it programatically.
if your dropzone element id is 'my-awesome-dropzone':
<form action="/file-upload"class="dropzone" id="my-awesome-dropzone"></form>
Dropzone automatically will create a property with the camelized id name 'myAwesomeDropzone' and attach it to the current object.
So you set the Dropzone options by doing:
//myAwesomeDropzone = camelized version of ID = my-awesome-dropzone
Dropzone.options.myAwesomeDropzone = {
addRemoveLinks: true
}
I've made this plunker with minimun setup for you, just add your request config like you did before and it should work, i set the addRemoveLinks to true so you can see that they are working:
https://plnkr.co/edit/9850jCOpTwjSSxI1wS1K?p=info
I am attempting to use the jQuery File Upload Plugin here
The behavior I want is similar to the home page that loads - i.e - the ability to select multiple files - when selected I don't need the button to upload files individually (just remove with the cancel button individually) and remove all with the cancel button along the top bar
I am developing my site in c# mvc and the file gets uploaded to a ECM solution via CMIS Browser Bindings so I dont actually hit an MVC controller method. As I am using Browser Bindings I need to upload each file individually to the CMIS Endpoint. The code works fine doing an auto data submit for each file
So the working code I have is:
$('#uploadFile').fileupload({
replaceFileInput: false,
singleFileUploads: true,
add: function (e, data) {
$.each(data.files, function (index, file) {
data.url = 'mycmis_url';
data.type = 'POST';
data.submit();
});
},
done: function (e, data) {
alert("Done");
}
});
If I do have 3 files selected to upload I will get 3 'Done' alerts but the 3 files all upload successfully. However as mentioned the behavior I want is one Uppload All button that would trigger the upload for each of my selected files. I have the code below:
$('#uploadFile').fileupload({
replaceFileInput: false,
singleFileUploads: true,
autoUpload: false,
add: function (e, data) {
$.each(data.files, function (index, file) {
data.url = 'mycmis_url';
data.type = 'POST';
});
$("#uploadAllFilesBtn").unbind('click').on('click', function () { data.submit(); });
},
done: function (e, data) {
alert("Done");
}
});
So I have set the autoUpload property to false but if I select two files and then click my Upload All Files button as my uploadAllFiles button is outside my each loop if my first selected file is called foo.txt and my 2nd selected file is bar.txt it will only upload bar.txt.
Has anyone got any idea how I could have a button called upload all that would trigger a data.submit for each individual file?
Incorporating code from your later question:
$('#uploadFile').fileupload({
replaceFileInput: false,
singleFileUploads: true,
add: function(event, data) {
data.url = 'myUrl';
data.type = 'POST';
data.context = $('<tr>'
+ '<td><strong>Selected File : </strong>' + data.files[0].name + '</td>'
+ '<td> </td>'
+ '<td><button type="button" class="removeBtn btn btn-default">'
+ '<span class="glyphicon glyphicon-remove-circle"></span>'
+ 'Remove File</button></td>'
+ '</tr>')
.appendTo('#files')
.data('data', data);
}
});
$('#files').on('click', '.removeBtn', function() {
$(this).closest('tr').remove();
});
$('#uploadAllFiles').click(function() {
var jqXHRs = [];
$('#files').find('tr').each(function() {
jqXHRs.push($(this).data('data').submit());
});
$.when.apply($, jqXHRs).done(function() {
alert('done');
});
});
Note:
Since you have singleFileUploads set to true, the data.files array will always contain exactly one file.
The data is attached to the <tr> element using jQuery's .data() function.
For the "Remove" buttons, the code is using event delegation, which was suggested by #Ekansh's answer to your other question.
I need to select a file to upload with dojox/Uploader by clicking on a div not related to the widget.
I've tried using on.emit, but nothing happens (also click(), onclick() etc... on domNodes..)
This is my code:
var myUploader = new dojox.form.Uploader({
id : 'myUploader',
url : baseUrl + '/upload/form',
style : {
'overflow': 'hidden',
'position': 'relative',
'opacity' : 0
}
},"uploaderHolder");
myUploader.startup();
var importButtonNode = dom.byId("importDivButton");
on(importButtonNode,"click",function(evt) {
on.emit(myUploader.domNode, "click", {
bubbles: true,
cancelable: false
});
The widget must be hidden, so I can't press widget select button. I need open select file dialog by click other div so... how can I open the file browser programmatically to select a file?
Well, I find out a solution. I take a widgets inner node to call click, and attach a listener to the Uploader change event and complete event...
First, attach click event to a node.
var importButtonNode = dom.byId("myImportDiv");
on(importButtonNode,"click",function(evt) {
myUploader.domNode.childNodes[0].click();
});
Attach to Uploader change and complete events a handler
myUploader.on("change",function(evt){
if(evt[0].type != FileTypes.XSLX_FILE_TYPE){
alert("Error file type must be XLSX");
} else {
var formData = new Object();
formData.idProject = project.id;
myUploader.upload(formData);
}
});
myUploader.on("complete",function(evt){
alert("File Uploaded");
// do things
});
In my case I need send formdata without a form... so use de upload method. Also the file must be XLSX.
I hope this helps.
Regards
I am using a fileupload event assigned to #fileupload control. When I put this code in a static page it works well, but I want this control to load in a Javascript template like this:
<script type="text/template" id="propertyCollectionTemplate">
<span id="firstUpload" class="btn btn-success fileinput-button">
<i class="glyphicon glyphicon-plus"></i>
<span>Select files...</span>
<!-- The file input field used as target for the file upload widget -->
<input id="fileupload" type="file" name="files[]" multiple>
</span>
</script>
this template is loaded when clicking in one table row in my stage
$('table.collection tbody tr').click(function (e) {
e.preventDefault();
var m = page.properties.get(this.id);
page.showDetailDialog(m);
});
In my showDetailDialog function have this code:
showDetailDialog: function (m) {
// show the modal dialog
$('#propertyDetailDialog').modal({ show: true });
// ... fecth all data for my other controls....
This is my upload event bound in static mode:
$('#fileupload').fileupload({
url: page.url,
dataType: 'json',
done: function (e, data) {
alert("hola");
$.each(data.result.files, function (index, file) {
$('#propertyimage').val("/propertylocator/upload/server/php/files/" + file.name);
});
$('#progress .progress-bar').css('width', 0 + '%');
},
progressall: function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
$('#progress .progress-bar').css('width', progress + '%');
}
}).prop('disabled', !$.support.fileInput).parent().addClass($.support.fileInput ? undefined : 'disabled');
If I copy and paste this event in Chrome console when modal popup is loaded this work well, but I don't know how to delegate this event once I have loaded the template.
There are two ways:
First way:
Initiate fileupload initially (before inserting template) and set the properties on change:
$('#fileupload .files').on('change', ':file', function (e) {
$('#fileupload').fileupload('add', {
fileInput: $(this)
});
});
More details here: https://github.com/blueimp/jQuery-File-Upload/issues/1260
Second way:
Bind fileupload after inserting template in a callback, like:
$('table.collection tbody tr').click(function (e) {
// your 'click' code
e.preventDefault();
var m = page.properties.get(this.id);
page.showDetailDialog(m);
// bind fileupload
$('#fileupload').fileupload({
// ...
});
});
More details here: jQuery File Upload not working when file input dynamically created
Rather than having multiple file uploads on a single dropzone element - is it possible to have multiple dropzone elements on a single page?
It seems dropzone isn't even triggering after the select dialog when there are multiple elements,each with their own dropzone initialized
The typical way of using dropzone is by creating a form element with the class dropzone:
<form action="/file-upload"
class="dropzone"
id="my-awesome-dropzone"></form>
That's it. Dropzone will find all form elements with the class dropzone, automatically attach itself to it, and upload files dropped into it to the specified action attribute. You can then access the dropzone element like so:
// "myAwesomeDropzone" is the camelized version of the HTML element's ID
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("Naha, you don't.");
}
else { done(); }
}
};
As far as i know , you can create your own dropzone , then it's possible to have multiple dropzone elements.
// Dropzone class:
var myDropzone = new Dropzone("div#myId", { url: "/file/post"});
// jQuery
$("div#myId").dropzone({ url: "/file/post" });
Yes, you can have an unlimited amount of dropzones on a single page.
Example:
<form action="/controller/action">
<div class="dropzoner" id="dropzone1"></div>
<div class="dropzoner" id="dropzone2"></div>
</form>
<script>
Dropzone.autoDiscover = false; // Very important
InitializeDropzones();
function InitializeDropzones() { // You only need to encapsulate this in a function if you are going to recall it later after an ajax post.
Array.prototype.slice.call(document.querySelectorAll('.dropzoner'))
.forEach(element => {
if (element.dropzone) {
element.dropzone.destroy();
} // This is only necessary if you are going to use ajax to reload dropzones. Without this, you will get a "Dropzone already exists" error.
var myDropzone = new Dropzone(element, {
url: "/controller/action",
headers: {
"headerproperty": value,
"headerproperty2": value2
},
});
})
}
</script>
Some notes that might save someone time when dealing with multiple dropzones:
After reloading any elements via ajax that have a dropzone attached to them, you will need to reinitialize that dropzone onto the element.
For instance:
myDropzone.on("success", function (response) {
toastr[show a toastr];
$("#ContainerThatHasDropzones").load("/controller/action/" + id, function() {
Dropzone.discover(); // This is very important. The dropzones will not work without this after reloading via ajax.
InitializeDropzones();
});