Liveview file drag & drop with phx-drop-target

This is my first post in the forum so – hello everyone!

I’m fairly new to Elixir and programming in general so excuse me for my noob question.

I’m exploring the file upload feature in Liveview and am trying to create a drag and drop zone to load up files in the live_file_input. I read in the documentation that drag & drop support is done by annotating the dropable container with phx-drop-target="<%= @uploads.photo.ref %>".

I have the uploader in a stateful Live Component. this the mount:

  def mount(socket) do
    {:ok,
     socket
     |> assign(:uploaded_files, [])
     |> allow_upload(:cover_photo,
       accept: ~w(.png .jpeg .jpg),
       max_file_size: 2_000_000,
       external: &presign_entry/2)}
  end

and template:


 <div class = "flex items-center">
      <form id="cover-photo-upload"
                 phx-change = "validate"
                 phx-submit = "save" phx-target = "<%=@myself %>" %>
           <div class="flex"
                  id = "dropzone"
                  phx-hook = "DragDrop"
                  phx-drop-target="<%= @uploads.cover_photo.ref %>">
                  <%= live_file_input @uploads.cover_photo %>
                 <button type="submit" class ="text-white" phx-disable-with = "Uploading">
                 Upload
                </button>
         </div>
 </div>

Drag & drop isn’t not working for me and it is probably because I am missing something. I’m sure if I have to implement anything on the javascript side. Right now, I have a Hook that highlights the container on dragenter and dragover.

Hooks.DragDrop = {
  mounted() {
    let dropArea = document.getElementById(this.el.id);
    [("dragenter", "dragover", "dragleave", "drop")].forEach((eventName) => {
      dropArea.addEventListener(eventName, preventDefaults, false);
    });
    function preventDefaults(e) {
      e.preventDefault();
      e.stopPropagation();
    }
    ["dragenter", "dragover"].forEach((eventName) => {
      dropArea.addEventListener(eventName, highlight, false);
    });

    ["dragleave", "drop"].forEach((eventName) => {
      dropArea.addEventListener(eventName, unhighlight, false);
    });
    function highlight(e) {
      dropArea.classList.add("bg-red-400");
    }

    function unhighlight(e) {
      dropArea.classList.remove("bg-red-400");
    }
  },
};

Thanks for your help!

Pedro

1 Like

Did you try without your hook connected? This is just a hunch, but I see you’re doing event.stopPropagation() in your code on the drop event. It’s the same event LiveView listens to, thus I’m wondering if this could be issue.

2 Likes

Hey Sfusato,

Thanks for your reply! I tried without the Hook but the drag and drop is still not working.

sfusato, you were correct after all – the event.stopPropagation() was preventing Liveview upload to do its job!