Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't preventDefault() on drop event on a div with Svelte

I'm trying to implement a file dropper on a <div> as a Svelte component. I've tried every combination of preventDefault but the browser still loads the dropped file instead of passing it to the component.

<script>
    function handleDrop(event) {
        event.preventDefault();
        console.log("onDrop");
    }

    function handleDragover(event) {
        console.log("dragOver");
    }
</script>

<style>
    .dropzone {
        display: block;
        width: 100vw;
        height: 300px;
        background-color: #555;
    }
</style>

<div class="dropzone" on:drop|preventDefault={handleDrop} 
    on:dragover|once|preventDefault={handleDragover}></div>

I've tried with and without event.preventDefault(); in handler functions. Also tried with on:dragenter event and different combinations of modifiers, i.e. with stopPropagation. The browser still opens the dropped file. What am I doing wrong? Thanks!

(UPDATE) FIX: Okay, the culprit was the |once modifier. Once removed from the on:dragover in <div> everything works great, except that dragover event fires continuously while dragging across the div. event.preventDefault(); inside handler functions is not needed as the |preventDefault modifier works correctly. Here is the code (omitting <style> for brevity):

<script>
    function handleDrop(event) {
        console.log("onDrop");
    }
    function handleDragover(event) {
        console.log("onDragOver");
    }
</script>

<div class="dropzone" on:drop|preventDefault={handleDrop} 
    on:dragover|preventDefault={handleDragover}></div>

Not submitting this as an answer yet, because I would like to find out why I can't use |once modifier for dragover event, which would be useful for my app. Thanks!

like image 583
Eximorp Avatar asked Jun 22 '19 10:06

Eximorp


1 Answers

Problem:

This is a common gotcha rooted in HTML drag-and-drop (not Svelte's fault), where the last dragover event must be canceled in order to cancel drop. Looking at Svelte's once directive, it's just a closure that runs your handler one time. However, dragover will fire multiple times before being dropped, so the immediately preceding dragover is not prevented.

Solution:

Just include the directive without a handler:

<div 
   on:dragover|preventDefault
   on:drop|preventDefault={handler} 
>
like image 166
JeffD23 Avatar answered Sep 18 '22 10:09

JeffD23