By default, the browser prevents anything from happening when dropping something onto most HTML elements. To change that behavior so that an element becomes a drop zone or is droppable, the element must have both ondragover and ondrop event handler attributes.
Drag and drop file uploads happen when you drag one or more files from an underlying platform's file manager and drop them onto a web page for upload. A preview of the image indicates the upload has begun. Many JavaScript libraries create this type of drag and drop file upload feature with a few lines of code.
You can add a event listener to the window that calls preventDefault()
on all dragover and drop events.
Example:
window.addEventListener("dragover",function(e){
e = e || event;
e.preventDefault();
},false);
window.addEventListener("drop",function(e){
e = e || event;
e.preventDefault();
},false);
After a lot of fiddling around, I found this to be the stablest solution:
var dropzoneId = "dropzone";
window.addEventListener("dragenter", function(e) {
if (e.target.id != dropzoneId) {
e.preventDefault();
e.dataTransfer.effectAllowed = "none";
e.dataTransfer.dropEffect = "none";
}
}, false);
window.addEventListener("dragover", function(e) {
if (e.target.id != dropzoneId) {
e.preventDefault();
e.dataTransfer.effectAllowed = "none";
e.dataTransfer.dropEffect = "none";
}
});
window.addEventListener("drop", function(e) {
if (e.target.id != dropzoneId) {
e.preventDefault();
e.dataTransfer.effectAllowed = "none";
e.dataTransfer.dropEffect = "none";
}
});
<div id="dropzone">...</div>
Setting both effectAllow
and dropEffect
unconditionally on the window causes my drop zone not to accept any d-n-d any longer, regardless whether the properties are set new or not.
For jQuery the correct answer will be:
$(document).on({
dragover: function() {
return false;
},
drop: function() {
return false;
}
});
Here return false
will behave as event.preventDefault()
and event.stopPropagation()
.
To allow drag-and-drop only on some elements, you could do something like:
window.addEventListener("dragover",function(e){
e = e || event;
console.log(e);
if (e.target.tagName != "INPUT") { // check which element is our target
e.preventDefault();
}
},false);
window.addEventListener("drop",function(e){
e = e || event;
console.log(e);
if (e.target.tagName != "INPUT") { // check which element is our target
e.preventDefault();
}
},false);
Note: Although the OP did not ask for an Angular solution, I came here looking for that. So this is to share what I found to be a viable solution, if you use Angular.
In my experience this problem first arises when you add file drop functionality to a page. Therefore my opinion is that the component that adds this, should also be responsible for preventing drop outside of the drop zone.
In my solution the drop zone is an input with a class, but any unambiguous selector works.
import { Component, HostListener } from '@angular/core';
//...
@Component({
template: `
<form>
<!-- ... -->
<input type="file" class="dropzone" />
</form>
`
})
export class MyComponentWithDropTarget {
//...
@HostListener('document:dragover', ['$event'])
@HostListener('drop', ['$event'])
onDragDropFileVerifyZone(event) {
if (event.target.matches('input.dropzone')) {
// In drop zone. I don't want listeners later in event-chain to meddle in here
event.stopPropagation();
} else {
// Outside of drop zone! Prevent default action, and do not show copy/move icon
event.preventDefault();
event.dataTransfer.effectAllowed = 'none';
event.dataTransfer.dropEffect = 'none';
}
}
}
The listeners are added/removed automatically when component is created/destroyed, and other components using the same strategy on the same page do not interfere with each other due to the stopPropagation().
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With