Drag and drop: keeping track of the item being dragged

Hello, I’m working with halogen trying to implement drag and drop. In vanilla JS one gets the item that is being dragged from the event.

function onDragStart(event) {
  event
    .dataTransfer
    .setData('text/plain', event.target.id);
}

In purescript i have this function

import Web.Event.Event as WEE
import Web.HTML.Event.DragEvent as WHDE

data Action = Drag | New

go_drag :: DragEvent -> Maybe Action
go_drag e = trace (WEE.target $ WHDE.toEvent e) \_ -> Just Drag

So i can get the target. But what then? I know i should expand the Drag data constructor to take additional values, but what should i put in there? I can’t find a function to access the data-id property of the target.

Or am i going about this completely the wrong way?

I was not planning to use the dataTransfer attribute actually … but maybe i will have to (need to do some more reading about this in MDN docs)

Any help would be much appreciated.

It would help if you gave us some more context of what you want to accomplish. Putting something in dragData might be the path of least resistance if you want to drag and drop things between components, but it probably isn’t necessary.

Hi @natefaubion. I have two lists (ul elements) which i want to drag items between. At the moment these are just simple text but later it will be more complicated elements. These list are at the moment in the same Halogen component.

What do you mean with dragData ?

dragData just lets you store stringy data, which may be a convenient if you need to drag among different components or between windows. Otherwise I would start by putting something in component state to represent the item that you are dragging. Then in other drag/drop handlers you can pull that out of state and do any checks you need to. In your above example, I would add parameters to your Drag constructor to hold the thing you are dragging. When you handle that action, you should put it in state.

Hi @natefaubion i guess with dragData you mean the data when using the setData method on the DataTransfer object.

I like your idea of putting a representation of the dragged item in state.

What would the representation be though? I can’t access the data-id property on the html element for example. This is where i immediately get stuck.

You haven’t said what data-id is or why you need. web-dom bindings provide all you need to convert and get properties like that though, you just have to track down the interfaces (it works best through typed holes). I don’t recommend storing data like that in the DOM though if you can help it. If you are using a specific UI library I could give you other recommendations.

what is data-id

When onDragStart triggers the event carries within it the target (that is the element being dragged). My idea was to identify this element by some properties in the dom like data-id mdn.

why do i think i need it

I didn’t see a possibility to instead get the Halogen types that represent this html element, or the data being used to construct these halogen html types. Therefor i believed i can only access the DOM.

Thanks for pointing to web-dom, i found two methods that seem useful

https://pursuit.purescript.org/packages/purescript-web-dom/4.0.0/docs/Web.DOM.Element#v:fromEventTarget

https://pursuit.purescript.org/packages/purescript-web-dom/4.0.0/docs/Web.DOM.Element#v:getAttribute

you have to track down the interfaces

not sure what you mean by this

I don’t recommend storing data like that in the DOM though if you can help it

Well, like i said above i think i need to go through the dom because the Event does not give me purescript data types (as far as i know). So my idea was that after extracting the identifier from the dom i could then do a lookup to get the purescript data type back. This is all a bit inconvenient of course, and maybe there could be a library for this. But i just didn’t see another way.

I’m using halogen.

Thanks for the help !

If you are using Halogen, you can close over values in your handler and put them in your constructor.

render state =
  HH.div' $ state.items <#> \item ->
    HH.div
      [ HP.onDragStart \ev -> Just (Action ev item) ]
      [ ... ]

By “interfaces” I mean the various interfaces that make up the DOM specification. web-dom types mirror the DOM spec.

2 Likes

Thanks that helped a lot. I have this part typechecked at the moment. I can just pass purescript data by the data constructor.

What about the drop area though? I think i have to use the DOM in this instance to identify the identifier of the target element. Or is this also in this case a way to immediately access the data from which the target element html is constructed ?