You can use JS Interop.
Given this html
<div id="draggable" draggable="true" style="width:100px; height:100px; background-color:gold;">Draggable</div>
<div id="drop_zone" style="width:300px; height:300px; background-color:pink;"> Drop Zone</div>
here is a simple example:
- Set the element
draggable
and set the phx-hook
also it’s probably a good idea to give it an id
.
<div id="draggable" phx-hook="draggable_hook" draggable="true" >Draggable</div>
- Give the drop zone a hook.
<div phx-hook="drop_zone">Drop Zone</div>
- In apps.js add a draggable_hook object. In its mounted method add your
dragstart
event handler.
let Hooks = {}
Hooks.draggable_hook = {
mounted() {
this.el.addEventListener("dragstart", e => {
e.dataTransfer.dropEffect = "move";
e.dataTransfer.setData("text/plain", e.target.id); // save the elements id as a payload
})
}
}
- Add your
drop_zone
hook and register event handlers for dragover
and drop
.
mounted() {
this.el.addEventListener("dragover", e => {
e.preventDefault();
e.dataTransfer.dropEffect = "move";
})
this.el.addEventListener("drop", e => {
e.preventDefault();
var data = e.dataTransfer.getData("text/plain");
this.el.appendChild(e.view.document.getElementById(data));
})
}
}
For more details on Drag and Drop events go to Modzilla’s docs
- Finally register your hooks with live view.
let liveSocket = new LiveSocket("/live", Socket, {hooks: Hooks})
here is the example live view:
#lib/example_web/live/dragndrop_live.ex
defmodule ExampleWeb.DragndropLive do
use Phoenix.LiveView
require Logger
def mount(_session, socket) do
Logger.info("MOUNT #{inspect(self())}")
{:ok, socket}
end
def render(assigns) do
Logger.info("RENDER #{inspect(self())}")
~L"""
<div id="draggable" phx-hook="draggable_hook" draggable="true" style="width:100px; height:100px; background-color:gold;">Draggable</div>
<div phx-hook="drop_zone" style="width:300px; height:300px; background-color:pink;"> Drop Zone</div>
"""
end
def update(assigns, socket) do
{:ok, socket}
end
end
// assets/js/app.js
import css from "../css/app.css"
import "phoenix_html"
import {Socket} from "phoenix"
import socket from "./socket"
import LiveSocket from "phoenix_live_view"
.
.let Hooks = {}
Hooks.draggable_hook = {
mounted() {
this.el.addEventListener("dragstart", e => {
e.dataTransfer.dropEffect = "move";
e.dataTransfer.setData("text/plain", e.target.id); // save the elements id as a payload
})
}
}
Hooks.drop_zone = {
mounted() {
this.el.addEventListener("dragover", e => {
e.preventDefault();
e.dataTransfer.dropEffect = "move";
})
this.el.addEventListener("drop", e => {
e.preventDefault();
var data = e.dataTransfer.getData("text/plain");
this.el.appendChild(e.view.document.getElementById(data));
})
}
}
let liveSocket = new LiveSocket("/live", Socket, {hooks: Hooks})
liveSocket.connect()