Skip to content

interact.js

Created: 2016-06-13 15:38:27 -0700 Modified: 2018-08-15 09:05:11 -0700

For dropzones, you have access to “ondropmove”, which will get hit every time the element being dragged is moved over the dropzone.

Drag event handlers aren’t being hit

Section titled Drag event handlers aren’t being hit

Element doesn’t exist in DOM

This was actually due to how I was using things in React. My Parent component was only rendering my Child component if “isDragging” was true, which was set in the ondropactivate function. The problem was that the Child component didn’t have a chance to register event listeners for the drag function since it didn’t even exist in the DOM until the drag event had already started.

My solution was to have the DOM elements always present but with “display:none” on them, that way they could still get event listeners.

Reusing “interact” objects

I ran into a huge issue on August 13th-14th (2018) where I had this setup:

  1. HardwareSlot renders a Slot. The Slot should be a drop target.
  2. Slot is wrapped by an HOC named “makeDraggable” which makes the slot draggable of course.

The above means that I needed the same DOM element to be draggable and a drop target. At first, I didn’t realize I was operating on the same element, so I just did “interact(this.refToDraggable)” from both locations. It works just fine until you call “unset” I think, then everything just starts screwing up and you lose event handlers. There are essentially only two high-level solutions:

  1. Make another DOM element and add the handlers to that
  2. Only have one “interact” for each DOM element

I ended up going with solution #2. For me, that made my “makeDraggable” componentDidMount look like this (it’s a little wonky, but it works):

componentDidMount() {
assert(
!_.isNil(this.refToDraggable),
'Forgot to set refToDraggable by calling initializeRefs from wrapped component'
);
this.interactable = interact(this.refToDraggable)
.draggable({
manualStart: true,
onmove: this.dragMoveListener.bind(this),
onend: this.dragEndListener.bind(this),
})
.on('move', this.onDragMove.bind(this));
if (_.isFunction(this.wrappedComponentRef.getDropzoneParams)) {
const dropzoneParams = this.wrappedComponentRef.getDropzoneParams();
if (_.isObject(dropzoneParams)) {
this.interactable.dropzone(dropzoneParams);
}
}
}

The creator of InteractJS does write (reference) that multiple “Interactable” objects can be returned if you specify different arguments to “interact”, e.g.

interact(‘.draggableCssClass’)

interact(draggableDomElement)

interact(‘#draggableId’)

However, you still seem to run into an issue calling “unset” on any of these.

Otherwise-unexplained errors, e.g. errors about calling setState from an unmounted component, or errors about a “props” not existing that you expect

Section titled Otherwise-unexplained errors, e.g. errors about calling setState from an unmounted component, or errors about a “props” not existing that you expect

This is very likely due to a “dead” component still listening for events, meaning you didn’t clean up your “interact()” call from componentWillUnmount.

If you call “interact()” from inside componentDidMount, then you should save it off to a class variable (e.g. “this.interactable = interact(…)”) and in componentWillUnmount, do something like this:

if (!_.isNil(this.interactable)) {

this.interactable.unset(); // stops listening to events

this.interactable = null;

}

Drag events getting triggered incorrectly (the setEventXY bug)

Section titled Drag events getting triggered incorrectly (the setEventXY bug)

GitHub issue reference: https://github.com/taye/interact.js/issues/406