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 }, {});
});
};
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'm trying to create a simple click catcher where if you click .image-class the javascript will take the href from another element with a class name of .btn and send you to it's destination. Though I keep getting errors on lines 7 & 10 saying that undefined is not a function. How do I make this work?
<script>
var ClickCatcher=
{
init:function(){
var link = jQuery('.btn')[1].href;
var imgCatch = jQuery('.image-class');
imgCatch.addEventListener("click", ClickCatcher.clickListener, false);
},
clickListener:function(){
window.location = link;
}
};
ClickCatcher.init();
</script>
You can do this with jquery with a simple click event
jQuery('.image-class').on('click', function (){
window.location = jQuery('.btn').eq(1).attr('href');
});
But if you still want to write in the way you have you can do:
var ClickCatcher = {
init: function () {
jQuery('.image-class').on('click', function (){
window.location = jQuery('.btn').eq(1).attr('href');
});
}
};
ClickCatcher.init();
Just make sure to fire the init method after dom load.
update: One issue with it is that you have coded your target etc in the code rather then pass it, so its going to be hard to reuse, you'd be better off doing:
var ClickCatcher = {
init: function ($button, loc) {
$button.on('click', function (){
window.location = loc;
});
}
};
ClickCatcher.init(jQuery('.image-class'), jQuery('.btn').eq(1).attr('href'));
That way the internal working is seperate from the dom (as you are passing the dom dependencies to the function.
#atmd showed a very good way of doing this. If you just want to know what your mistake was though. It is wa an error in your jQuery stament to get the btn href
jQuery('.btn')[1].href
you need to call the attr function and then get the href attr. and use .eq(1) to reduce the set to the first btn
jQuery('.btn').eq(1).attr('href);
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();
});
I'm trying to get the jquery loadmask addon to work that will mask elements (for loading content). I'm using knockout.js, and when if I mask an element outside of my viewmodel it works, but I want to mask it upon submitting a POST request, and then unmask when I receive it. I'm getting an "object has no method mask" error from this. I'm not quite sure how to go about setting up an object to access it.
This works, but it's not what I want. I noted in the code where I would like to call mask from
<div id = "register_container">
<div data-bind="visible: register()">
<div id = "register_form"> <!--this is the div I want to mask -->>
<button data-bind="click: submitRegistration">Submit</button>
</div>
</div>
</div>
function MyViewModel(){
self.submitRegistration = function(){
//I want to mask here. When I try it says Object[object object] has no method mask
$.post....{
if(data.result == success){
// andunmask here
}
}
}
}
$("#register_form").mask("Waiting..."); //the masking works when I place it here, but it's always enabled and I want it inside the viewmodel where I noted so it only works when the POST request is in process
That's great and all, but I want to mask something from inside the viewmodel where I noted. How can I accomplish this?
I see several things that could be the problem.
Frist, you're doing assignment as opposed to comparison in the if statement. Use this instead:
if(data.result == success){
or even
if(data.result === success){
Second is the fact that I don't quite understand your code self.submitRegistration(){, which typically looks more like this:
var MyViewModel = function () {
var self = this;
self.submitRegistration = function() {
};
};
Then, if I mock the $.post call, it would work like this:
var MyViewModel = function () {
var self = this;
self.register = ko.observable(true);
self.submitRegistration = function() {
$("#register_form").mask("Waiting...");
// Mock $.post
window.setTimeout(function () {
if (1 == 1) {
// andunmask here
$("#register_form").unmask();
}
}, 3000);
}
};
ko.applyBindings(new MyViewModel());
See this fiddle for a demo.
You could even have Knockout help you find the element to look for:
See this updated fiddle for a demo of that.
// Use the "event" parameter to find the element...
self.submitRegistration = function(data, event) {
$(event.target).closest('#register_form').mask("Waiting...");
Hope it helps.
I'm trying to bind an onChange event of one FilteringSelect to populate another FilteringSelect.
// View
dojo.addOnLoad(function () {
dojo.connect(dijit.byId('filterselect1'), 'onChange', function () {
dijit.byId('filterselect2').store = new dojo.data.ItemFileReadStore(
{ url: "/test/autocomplete/id/" + dijit.byId("filterselect1").value }
);
});
});
The JSON is generated from what I can tell correctly from a Zend Action Controller using a autoCompleteDojo helper.
// Action Controller
public function autocompleteAction()
{
$id = $this->getRequest()->getParam('id');
$select = $this->_table->select()
->from($this->_table, array('id','description'))
->where('id=?',$id);
$data = new Zend_Dojo_Data('id', $this->_table->fetchAll($select)->toArray(), 'description');
$this->_helper->autoCompleteDojo($data);
}
I receive the JSON from the remote datastore correctly, but it does not populate the second FilteringSelect. Is there something else I need to do to push the JSON onto the FilteringSelect?
I couldn't believe this was causing the problem, but the whole issue boiled down to the fact that it appears that a dojo ItemFileReadStore REQUIRES the label property of the JSON to be "name". In the end this is all that it required to wire them together.
dojo.addOnLoad(function () {
dijit.byId('filtering_select_2').store = new dojo.data.ItemFileReadStore({url: '/site/url'});
dojo.connect(dijit.byId('filtering_select_1'), 'onChange', function (val) {
dijit.byId('filtering_select_2').query.property_1 = val || "*";
});
});
UPDATE: The property within Zend form has been fixed as of ZF 1.8.4
Try console.log() in the event to see if it is launched. Changing the store should work, however for other widgets like grid you have also to call refreshing methods.