react-dnd / react-dnd-html5-backend

HTML5 backend for React DnD [Legacy Repo]
MIT License
146 stars 97 forks source link

Conflict with drag and drop file upload #25

Open yesmeck opened 8 years ago

yesmeck commented 8 years ago

I have a drag and drop file upload area in the DragDropContext, but the handleTopDragOver prevents the drag event which makes my drag and drop upload component not working.

Any workaround to solve the problem?

gaearon commented 8 years ago

If you can take a look at what it would take to make a pull request that handles this case correctly, we might merge it. Unfortunately you’re on your own there because I don’t currently have time to work on this.

kn0ll commented 7 years ago

@gaearon removing line 446 and line 426 all together fixes the issue.

furthermore, if we are dragging a native item type, dropEffect is actually already set to none (at least, in Chrome 55.0.2). so i don't expect removing these lines to introduce any issues. your 2 cents? if this sounds OK to you i can submit a pull request.

awinecki commented 7 years ago

I am having a similar issue. I think the root cause is the same so I didn't file a separate issue.

In my case, I'm having a piece of UI that is split into tabs. One tab has React DND re-arrangable photos, the other tabs have React Dropzone to upload some files. What I've found is that after adding React DND, it's all rendered together (thus event binding from both libs are in effect).

This for me results in the React Dropzone not working. When I drag files into the dropzone, it highlights (dragover etc. events work ok), but when I drop, the files are not handled at all, just "return" (kinda like they were rejected). See:

reactdnd-vs-reactdropzone

I've identified the problem to be somewhere in handleTopDrop and handleTopDropCapture, or general with event handlers from 2 libs clashing with each other.

What I've found is that addEventListeners function takes target as an argument, but it's actually always invoked with window as it's arg. I might be doing something wrong, but I think these events should not be set up on global window document.

A crude fix:

in HTML5Backend.js:

addEventListeners(target) {
    // Overrides window with the actual drag'n'drop area container
    target = $('.js-uploaded-photos-container')[0];
    target.addEventListener('dragstart', this.handleTopDragStart);
    target.addEventListener('dragstart', this.handleTopDragStartCapture, true);
...

This is somewhat related to https://github.com/react-dnd/react-dnd/pull/632, but my problem is not multiple global window instances (as in juggling iframes etc.), but merely limiting the DND to a specific DOM element.

Any hints, @darthtrevino ?

awinecki commented 7 years ago

Alright, small update:

I was able to solve my problem using https://github.com/react-dnd/react-dnd/pull/632 addition of the DragDropContextProvider. It's crucial that it initializes backend and DragDropContext classes when it's rendered, and not when the JSes initially load. That enabled me to do this:

module.exports = React.createClass({

  componentWillMount() {
    this.el = $('.js-uploaded-photos-container')[0]
  },

  render() {
    return (
      <DragDropContextProvider backend={HTML5Backend} window={this.el}>
        <PhotoList {...this.props} />
      </DragDropContextProvider>
    )
  },

})

So my current simplest suggestion would be to rename this window props to something more generic, and then add some information in DOCS how one can use this to mitigate both multiple iframes issues and issues similar to mine / conflicts with other dropzone libs.

I don't see contributing.md anywhere, what's the protocol? I can submit some fixes and/or docs updates, but who's in charge here (since I assume you're a bit busy @gaearon)?

darthtrevino commented 7 years ago

Interesting, I'm not necessarily opposed to this idea, but is there anything preventing you from just using the @DragDropContext at the top level?

kn0ll commented 7 years ago

@awinecki are you certain it's not handleTopDragOver as the original filing suggests (and where i found the issue)? and would you be willing to try the fix i suggested?

also, if it's the same issue, i would wager that even with DragDropContextProvider, native file uploads would still fail so long as they are children of a DragDropContext.

edit: @darthtrevino the DragDropContext kills native file uploads. putting it on the top level prevents handleDrop (of a native file) from firing anywhere. see my comment here: https://github.com/react-dnd/react-dnd/issues/457#issuecomment-268964677

mathieumg commented 7 years ago

I'm having the same problem as @yesmeck and @kn0ll. More precisely, in https://github.com/react-dnd/react-dnd-html5-backend/blob/v2.1.2/src/HTML5Backend.js#L486-L487 dropTargetIds is undefined, so when it calls https://github.com/react-dnd/dnd-core/blob/v2.1.0/src/actions/dragDrop.js#L77-L78 the invariant throws an error.

awinecki commented 7 years ago

@kn0ll I've tried your handleTopDragOver fix (rm lines 426 and 446) but it's still the same for me. The original issue as found by @yesmeck is about having a dropzone within a DragDropContext (at least that's how I understand it), e.g.:

<MyComponent>
      <Stuff />
      <Stuff />
      <Dropzone />
      <MoreStuff />
</MyComponent>

module.exports = DragDropContext(HTML5Backend)(MyComponent)

Whereas my issue is the fact that HTML5Backend binds events like dragstart, dragend, dragenter, drop, dragover on global window, instead of just the DOM el of the wrapped component (see addEventListeners)

but is there anything preventing you from just using the @DragDropContext at the top level?

I'm not sure I know what you mean. If by top level you mean top of my React app, then I must say I don't have a SPA, but rather hybrid codebase, so my other Dropzone is rendered separately by another ReactDOM.render call.

Though again, using DragDropContextProvider works perfectly for me, though the naming is a bit misleading. Anyhow, I wonder why constraining the Drag area to a single DOM element is not the default behaviour?

Here's an illustration:

1) Without constraint – current default behaviour

no-constraint

2) With constraint (after applying the fix with DragDropContextProvider) – blue border are the bounds of the DOM element passed to DragDropContextProvider as window prop

with-constraint

scottfr commented 7 years ago

I think the issue is even more pervasive than so far described. The global binding on the drag events seems to prevent even native controls from working for me. For instance, in an input field you should be able to select text and drag it around within the field. When React-DND is enabled this behavior is broken in my app.

I'll try out the DragDropContextProvider to see if it solves the issue.

soulprovidr commented 7 years ago

@scottfr: I'm having the same issue - did you ever find a solution?

scottfr commented 7 years ago

No, I've been unable to find a solution.

schabluk commented 7 years ago

Same issue here.

The DragDropContextProvider doesn't work for me, because it has to be at top level app component. When used somwhere below the top level, it gives this error: https://github.com/react-dnd/react-dnd/issues/858.