I'm trying to create a files-drag & drop zone in Angular. I created dropzone.directive
and added it to the declarations in app.module.ts
.
My code compiles and I can launch everything. But when I try to drag files, the html doesn't respond to the files I drag over the zone. I have the feeling that I am missing something obvious which prevents dropzone.directive
from getting activated.
How come directive.ts
doesn't seem to get triggered?
My problem can easily be reproduced: You can just copy and paste the code below, there are no special imports required.
My dropzone.directive.ts reads as follows:
import { Directive, EventEmitter, HostBinding, HostListener, Output } from '@angular/core';
@Directive({
selector: '[Dropzone]'
})
export class DropzoneDirective {
@Output() onFileDropped = new EventEmitter<any>();
@HostBinding('style.opacity') private opacity = '1';
@HostBinding('style.border') private border = 'none';
@HostListener('dragover', ['$event']) public onDragOver(evt: any): any {
evt.preventDefault();
evt.stopPropagation();
this.opacity = '0.8';
this.border = 'dotted 2px #FF4D2A';
}
@HostListener('dragleave', ['$event']) public onDragLeave(evt: any): any {
evt.preventDefault();
evt.stopPropagation();
this.opacity = '1';
this.border = 'none';
}
@HostListener('drop', ['$event']) public ondrop(evt: any): any {
evt.preventDefault();
evt.stopPropagation();
this.opacity = '1';
this.border = 'none';
const files = evt.dataTransfer.files;
if (files.length > 0) {
this.onFileDropped.emit(files);
}
}
}
Then I declare my directive in the app.module:
import { DropzoneDirective } from './dropzone.directive';
@NgModule({
declarations: [
.....,
DropzoneDirective
],
imports: [
...,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
My component.ts:
export class WebshopOverzichtComponent implements OnInit {
allFiles: File[] = [];
constructor() { }
droppedFiles(allFiles: File[]| any): void {
const filesAmount = allFiles.length;
for (let i = 0; i < filesAmount; i++) {
const file = allFiles[i];
this.allFiles.push(file);
}
}
}
And finally, my component.html:
<div class="container text-center mt-5">
<h3 class="mb-5"> Drop zone Dragondrop </h3>
<!-- Applying Directive -->
<div class="dropzone" DropZone (onFileDropped)="droppedFiles($event)">
<div class="text-center">
Drop files here.<BR>
</div>
</div>
<div class="file-table">
<h3 class="m-3">List of Files</h3>
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">File Name</th>
<th scope="col">Size</th>
<th scope="col">Type</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let file of allFiles; let i = index">
<th scope="row">{{i+1}}</th>
<td>{{file.name}}</td>
<td>{{file.size}} Bytes</td>
<td>{{file.type}}</td>
</tr>
<tr class="text-center" *ngIf="allFiles.length === 0">
<td colspan="4"><strong>No files are uploaded</strong></td>
</tr>
</tbody>
</table>
</div>
</div>
You don't even need to use directive. Just use the input tag, set it on type="file" and use annotation multipe. Set the opacity in css en enlarge the input. Use the function in ts that I gave. It will work as drag & drop zone. Make a seperate button to perform the upload.
<div class="file-container">
<input class="file" type="file" multiple
(change)="onFileChange($event)" >
</div>
<button class="btn btn-primary" [disabled]="allFiles.length==0" (click)="uploadFiles(product.webshopnaam)">Upload</button>
css
.file-container{
width: 300px;
border: 4px dotted black;
}
.file{
opacity: 0;
padding: 1rem;
width: auto;
height: 1rem;
}
ts
allFiles: File[] = [];
onFileChange(event:any) {
for (var i = 0; i < event.target.files.length; i++) {
this.allFiles.push(event.target.files[i]);
}
this.allFiles.forEach(value => console.log(value.name));
}
async uploadFiles(naam:string):Promise<void>{
this.productService.uploadImages(this.allFiles, naam);
}
onFileChange(event:any) {
for (var i = 0; i < event.target.files.length; i++) {
this.allFiles.push(event.target.files[i]);
}
this.allFiles.forEach(value => console.log(value.name));
}
async uploadFiles(naam:string):Promise<void>{
this.productService.uploadImages(this.allFiles, naam);
}