Search code examples
angulardrag-and-drop

Angular - Drag-And-Drop to upload an attachment


I'm working on an Angular app similar to Trello and I need to implement drag-and-drop functionality for customers to be able to upload an attachment.

The thing is that there is already an 'Attach" function (Without drag and drop) used from another component and I would need to implement the drag-and-drop in the same way as the other function works. (I need to adopt this 'add attachment' function for drag and drop)

Here is a photo explanation: https://ibb.co/d5WcJfQ

I tried watching youtube videos and google-ing but I'm having a hard times implementing it correctly and as requested. Any suggestions would be much appreciated.

// HTML OF ATTACH COMPONENT
<span>
 <a class="quiet-button js-attach">
      <label class="custom-file-upload">
             <input (change)="onFileChange($event)" type="file"/>
              Add Attachment...
         </label>
     </a>

//TS FUNCTION 'onFileChange" That I need to adopt for drag-and-drop.`

onFileChange(event){

let files = event.target.files;
if (files.length > 0) {
  let formData: FormData = new FormData();
  for (let file of files) {
    formData.append('fileName', file, file.name);
  }
  let file = files[0];
  let attachmentData = <AttachmentInsert>{
    FileName : file.name,
    Path : ${this.cardHierarchy.BoardGuid}/${this.cardHierarchy.ListGuid}/${this.cardHierarchy.CardGuid}/`,
    Extension : this.getExtension(file.name),
    CreatedBy : this.currentUser.IdMember,
    IdCard : this.idCard
  };
  this.cardService.addAttachment(attachmentData).subscribe(data =>{
      let attachment : Attachment = data;
      formData.append('filePath',attachment.Path);
      this.cardService.uploadDocument(formData).subscribe(res => {
        this.getAttachments();

      });
  });

}

Solution

  • Here is a rough example of how you can achieve this. First, add drag and drop events in html file:

    <div (dragover)="onDragOver($event)" (drop)="onDropSuccess($event)">
      <label class="custom-file-upload">
        <input (change)="onChange($event)" type="file"/>
        Add Attachment...
      </label>
    </div>
    

    Implementation:

    onDragOver(event) {
        event.preventDefault();
    }
    
    // From drag and drop
    onDropSuccess(event) {
        event.preventDefault();
    
        this.onFileChange(event.dataTransfer.files);    // notice the "dataTransfer" used instead of "target"
    }
    
    // From attachment link
    onChange(event) {
        this.onFileChange(event.target.files);    // "target" is correct here
    }
    
    private onFileChange(files: File[]) {
        ...
    }
    

    To add the "processing" effect just create a variable and use it to add/remove the "processing" element:

    processing: boolean;
    ...
    private onFileChange(files: File[]) {
        this.processing = true;
        this.cardService.addAttachment(attachmentData).subscribe(data => {
            ...
            this.processing = false;
        });
    }
    

    and use it in html like this (the div will be displayed if processing class is set, and that will be only if processing variable is true):

    <div class="progress" [class.processing]="processing">
      Processing...
    </div>
    
    <!-- in "css" -->
    .progress {
      display: none;
    }
    .progress.processing {
      display: flex;    // or any way to display an element
    }
    

    I added a working example here.

    Hope this helps.