ember-drag-drop icon indicating copy to clipboard operation
ember-drag-drop copied to clipboard

drag-handle is not reconnected when component nested under draggable-object re-renders

Open les2 opened this issue 5 years ago • 6 comments

When rendering a dynamic list of components such as:

{{#each items as |item|}}
   {{#draggable-object content=item  dragHandle='.some-drag-handle'}}
      {{component item.componentImplName item=item}}
  {{/draggable-object}}
{{/item}}

For the initial render, everything works perfectly.

When the dynamic component re-renders because componentImplName changes, the HTML element with .some-drag-handle on it is not detected.

I haven't looked at code for ember-drag-drop, but I assume there's some code that runs on initial render after child component renders that isn't re-executed when the child is removed and re-rendered.

A workaround is to completely re-render all items in the list (but that would be an unnecessary distraction for the end-user).

Let me know if you would like me to debug more. I also wouldn't mind trying to fix the issue upstream but I might need some guidance for that.

les2 avatar Sep 23 '19 22:09 les2

The code in question is here: https://github.com/mharris717/ember-drag-drop/blob/master/addon/components/draggable-object.js#L40-L52

We would need to have an API to trigger disconnecting and re-connecting when a child component re-renders.

Once easy to imagine API is to {{yield draggableApi}} in draggable-object where draggableApi exposes a method called updateDragHandle(). When invoked (by the child component), the routine to setup the event listeners on the drag handle would be re-run.

Thoughts on this approach? I plan to monkey-patch this idea in our application soon and I'll report back how well it works.

The API design is lightly inspired by what I've seen in addons like ember-basic-dropdown and ember-power-select.

les2 avatar Sep 23 '19 23:09 les2

This actually seems more like just a bug to me. A re-render of the child component should not affect this. If you have a reproduction that would be helpful, but I think I can use one of the demos to reproduce that. It should be able to be handled using component lifecycle functions like componentDidUpdate.

dgavey avatar Sep 24 '19 13:09 dgavey

This actually seems more like just a bug to me. A re-render of the child component should not affect this. If you have a reproduction that would be helpful, but I think I can use one of the demos to reproduce that. It should be able to be handled using component lifecycle functions like componentDidUpdate.

When the component in question re-renders, the entire DOM of the component is torn down, so the element containing the dragHandle selector no longer has mouse events attached to it.

We might be able to reproduce the issue in an ember-twiddle, too (if it lets you use addons).

les2 avatar Sep 24 '19 14:09 les2

Yeah it makes sense, just not sure the best way to fix it, probably using contextual components.

dgavey avatar Sep 24 '19 14:09 dgavey

Could have observer on content property and reattach whenever that changes. But that would still be a problem when content is the same (e.g., an ember-data model) and changing a model property causes the drag-handle to re-render.

les2 avatar Sep 24 '19 15:09 les2

@les @dgavey

One observation I noticed: If you tap the handle first then touch/drag the handle.. it will work..

i.e. the draggable-object becomes draggable="true" then the drag events will fire when you move it around.

That indicates to me that the event listeners are still bound.. in some way at least.

I'm investigating code now to see if there is anything i can find

grapho avatar Oct 16 '19 22:10 grapho