-
-
Save darrenmothersele/7afda13d858a156ce571510dd78b7624 to your computer and use it in GitHub Desktop.
import { Directive, EventEmitter, HostBinding, HostListener, Input, Output } from '@angular/core'; | |
// Angular Drag and Drop File | |
// | |
// Add this directive to an element to turn it into a dropzone | |
// for drag and drop of files. | |
// Example: | |
// | |
// <div (appDropZone)="onDrop($event)"></div> | |
// | |
// Any files dropped onto the region are then | |
// returned as a Javascript array of file objects. | |
// Which in TypeScript is `Array<File>` | |
// | |
@Directive({ | |
selector: '[appDropZone]' | |
}) | |
export class DropZoneDirective { | |
// The directive emits a `fileDrop` event | |
// with the list of files dropped on the element | |
// as an JS array of `File` objects. | |
@Output('appDropZone') fileDrop = new EventEmitter<Array<File>>(); | |
// Disable dropping on the body of the document. | |
// This prevents the browser from loading the dropped files | |
// using it's default behaviour if the user misses the drop zone. | |
// Set this input to false if you want the browser default behaviour. | |
@Input() preventBodyDrop = true; | |
// The `drop-zone-active` class is applied to the host | |
// element when a drag is currently over the target. | |
@HostBinding('class.drop-zone-active') | |
active = false; | |
@HostListener('drop', ['$event']) | |
onDrop(event: DragEvent) { | |
event.preventDefault(); | |
this.active = false; | |
const { dataTransfer } = event; | |
if (dataTransfer.items) { | |
const files = []; | |
for (let i = 0; i < dataTransfer.items.length; i++) { | |
// If dropped items aren't files, reject them | |
if (dataTransfer.items[i].kind === 'file') { | |
files.push(dataTransfer.items[i].getAsFile()); | |
} | |
} | |
dataTransfer.items.clear(); | |
this.fileDrop.emit(files); | |
} else { | |
const files = dataTransfer.files; | |
dataTransfer.clearData(); | |
this.fileDrop.emit(Array.from(files)); | |
} | |
} | |
@HostListener('dragover', ['$event']) | |
onDragOver(event: DragEvent) { | |
event.stopPropagation(); | |
event.preventDefault(); | |
this.active = true; | |
} | |
@HostListener('dragleave', ['$event']) | |
onDragLeave(event: DragEvent) { | |
this.active = false; | |
} | |
@HostListener('body:dragover', ['$event']) | |
onBodyDragOver(event: DragEvent) { | |
if (this.preventBodyDrop) { | |
event.preventDefault(); | |
event.stopPropagation(); | |
} | |
} | |
@HostListener('body:drop', ['$event']) | |
onBodyDrop(event: DragEvent) { | |
if (this.preventBodyDrop) { | |
event.preventDefault(); | |
} | |
} | |
} |
Hi darrenmothersele, can you tell me how to use this snippet with input type = file? I tried this solution:
<input
type="file"
[(ngModel)]="imgValue"
[ngModelOptions]="{ standalone: true }"
id="companyLogo"
/>
and
imgValue: any = '';
onDrop(dropFiles: FileList) {
this.imgValue = dropFiles[0];
}
but i have error:
InvalidStateError: Failed to set the 'value' property on 'HTMLInputElement': This input element accepts a filename, which may only be programmatically set to the empty string.
You can't "set" the file on an input element in that way. What are you trying to do? Why do you need to set the input element file, rather than just handle the file drop in the onDrop
handler?
Works nicely! This is a great start to what I need to do.
How do you get all files recursively within folders if a folder is dropped?
I'm not sure. You might have to do something with the list of DataTransferItem from the DragEvent... docs:
https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItemList
https://developer.mozilla.org/en-US/docs/Web/API/DragEvent
There might be some useful info in this SO:
https://stackoverflow.com/questions/3590058/does-html5-allow-drag-drop-upload-of-folders-or-a-folder-tree
Thank you. I will try them out.
After using this directive to drag and drop a file onto the browser, the file is getting locked on windows. Even after completing the file upload and closing the browser tab, the file remains locked saying it is in use by chrome. I have to manually kill all chrome background processes to unlock the file. Same thing happens in edge. Anybody run into the same issue and find workaround?
Thanks so much for sharing this. Works great!