Open File Selection dojox/Uploader programmatically - javascript

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

Related

Laravel 5.2 & Dropzone.js - Remove (Delete) uploaded images

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

Multiple Dropzone in a single page

I'm using Dropzone without creating a dropzone form. It works great for me in this way.
But in this case I can not create another instance of Dropzone in my page.
var myDropzone1 = new Dropzone(
document.body,
{
url : "upload1"...
.
.
. some parameters
};
var myDropzone2 = new Dropzone(
document.body,
{
url : "upload'"...
.
.
. some parameters
};
When I do this, I'm getting the error Dropzone already attached.
It's possible, but you can't bind a second dropdzone on the same element, as you did. 2 Dropzones on one element makes no sense. 2x document.body in your solution atm. Try this...
HTML:
<form action="/file-upload" class="dropzone" id="a-form-element"></form>
<form action="/file-upload" class="dropzone" id="an-other-form-element"></form>
JavaScript:
var myDropzoneTheFirst = new Dropzone(
//id of drop zone element 1
'#a-form-element', {
url : "uploadUrl/1"
}
);
var myDropzoneTheSecond = new Dropzone(
//id of drop zone element 2
'#an-other-form-element', {
url : "uploadUrl/2"
}
);
I want to add something here because I have experienced problems with multiple dropzones on the same page.
In your init code you must remember to include var if putting a reference otherwise it isn't dealing with this instance of the dropzone rather trying to access/relate to the others.
Simple javascript but makes a big difference.
init: function(){
var dzClosure = this;
$('#Btn').on('click',function(e) {
dzClosure.processQueue();
});
Note: I'm not using Ajax in order to upload the image on server. For Ajax, One can use url. Attaching the doc DropzoneDoc. It's works like action.( Something like that. Check my solution you can get some idea to do it in your case.
When I working we dropzone, I faced a similar issue working with the Meteor framework.
In the case of Meteor Framework, dropzone is initialized in the below code. This will look different to you, it's the way to initialize in the Meteor framework.
In your case, you can find similarities when using the dropzone library.
Params are added as
params='{name: "Image1"}'
{{> dropzone url=getDropZoneImageUploadURL id='candidate-identity-photo-proof'
init=initFunction params='{name: "Image1"}'
acceptedMimeTypes= 'image/jpeg,image/png,image/jpg' maxFiles=1
success=uploadSuccessHandler maxFilesize=2 dictDefaultMessage= "Photo
ID Proof Photo"
previewsContainer='#upload-photo-id-holder'
previewTemplate=previewTemplateString}}
when the file is getting uploaded check "this" context as mentioned below code. You can use the params value to distinguish the image.
var initFunction = function () {
this.on("addedfile", function () {
if (this.files[1] != null) {
this.removeFile(this.files[0]);
}
});
this.on("sending", function (file, xhr, formData) {
console.log(this); // Here you can get the value
formData.append("type", "image");
});
this.on("error", function (fileInfo, errorMessage) {
var message = "ERROR";
showNotification("error", { message: message }, {});
});
};

Accept Image in Filefield ExtJs

I have a filefield componente in my application and I want to restrict it to only image files. I've found this question on stackoverflow:
How to restrict file type using xtype filefield(extjs 4.1.0)?
Add accept="image/*" attribute to input field in ExtJs
I'm using this code:
{
xtype:'filefield',
listeners:{
afterrender:function(cmp){
cmp.fileInputEl.set({
accept:'audio/*'
});
}
}
}
But this code only works the first time I click on "Examine" button, when I click again on it, the restriction dissapears. I've been looking for other events like onclick to write this code in that event, but I don't find the best way to do it, Anyone has any idea?
Greetings.
This is happening because when you submit form, it calls Ext.form.field.File#reset().
You should override reset() method like this, to keep you accept property:
{
xtype:'filefield',
reset: function () {
var me = this,
clear = me.clearOnSubmit;
if (me.rendered) {
me.button.reset(clear);
me.fileInputEl = me.button.fileInputEl;
me.fileInputEl.set({
accept: 'audio/*'
});
if (clear) {
me.inputEl.dom.value = '';
}
me.callParent();
}},
listeners:{
afterrender:function(cmp){
cmp.fileInputEl.set({
accept:'audio/*'
});
}
}
}

Multiple dropzone.js - single page

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();
});

Redefining a jQuery dialog button

In our application we use a general function to create jQuery dialogs which contain module-specific content. The custom dialog consists of 3 buttons (Cancel, Save, Apply). Apply does the same as Save but also closes the dialog.
Many modules are still using a custom post instead of an ajax-post. For this reason I'm looking to overwrite/redefine the buttons which are on a specific dialog.
So far I've got the buttons, but I'm unable to do something with them. Is it possible to get the buttons from a dialog (yes, I know) but apply a different function to them?
My code so far:
function OverrideDialogButtonCallbacks(sDialogInstance) {
oButtons = $( '#dialog' ).dialog( 'option', 'buttons' );
console.log(oButtons); // logs the buttons correctly
if(sDialogInstance == 'TestInstance') {
oButtons.Save = function() {
alert('A new callback has been assigned.');
// code for ajax-post will come here.
}
}
}
$('#dialog').dialog({
'buttons' : {
'Save' : {
id:"btn-save", // provide the id, if you want to apply a callback based on id selector
click: function() {
//
},
},
}
});
Did you try this? to override button's callback based on the need.
No need to re-assign at all. Try this.
function OverrideDialogButtonCallbacks(dialogSelector) {
var button = $(dialogSelector + " ~ .ui-dialog-buttonpane")
.find("button:contains('Save')");
button.unbind("click").on("click", function() {
alert("save overriden!");
});
}
Call it like OverrideDialogButtonCallbacks("#dialog");
Working fiddle: http://jsfiddle.net/codovations/yzfVT/
You can get the buttons using $(..).dialog('option', 'buttons'). This returns an array of objects that you can then rewire by searching through them and adjusting the click event:
// Rewire the callback for the first button
var buttons = $('#dialog').dialog('option', 'buttons');
buttons[0].click = function() { alert('Click rewired!'); };
See this fiddle for an example: http://jsfiddle.net/z4TTH/2/
If necessary, you can check the text of the button using button[i].text.
UPDATE:
The buttons option can be one of two forms, one is an array as described above, the other is an object where each property is the name of the button. To rewire the click event in this instance it's necessary to update the buttons option in the dialog:
// Rewire the callback for the OK button
var buttons = $('#dialog').dialog('option', 'buttons');
buttons.Ok = function() { alert('Click rewired!'); };
$('#dialog').dialog('option', 'buttons', buttons);
See this fiddle: http://jsfiddle.net/z4TTH/3/
Can you try binding your new function code with Click event of Save?
if(sDialogInstance == 'TestInstance') {
$('#'+savebtn_id).click(function() {
alert('A new callback has been assigned.');
// code for ajax-post will come here.
});
}

Categories