Skip to content
This repository has been archived by the owner on Jun 18, 2018. It is now read-only.

Conflict with drag and drop file upload #25

Open
yesmeck opened this issue Mar 24, 2016 · 12 comments
Open

Conflict with drag and drop file upload #25

yesmeck opened this issue Mar 24, 2016 · 12 comments

Comments

@yesmeck
Copy link

yesmeck commented Mar 24, 2016

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
Copy link
Member

gaearon commented Apr 4, 2016

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
Copy link

kn0ll commented Dec 23, 2016

@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
Copy link

awinecki commented Feb 9, 2017

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 react-dnd/react-dnd#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.

  • Am I doing something wrong and this is easily achievable?
  • If yes, let me know and I can perhaps post a PR with some more explanation to documentation
  • If not, how do you feel about adding some easy way to inject DOM element that'd be the DND limiting area element (e.g. DragDropContext(HTML5Backend, { limitToElement: MyComponent.DOMelement })(MyComponent)

Any hints, @darthtrevino ?

@awinecki
Copy link

awinecki commented Feb 9, 2017

Alright, small update:

I was able to solve my problem using react-dnd/react-dnd#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
Copy link
Member

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
Copy link

kn0ll commented Feb 9, 2017

@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: react-dnd/react-dnd#457 (comment)

@mathieumg
Copy link

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
Copy link

awinecki commented Feb 9, 2017

@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

  1. 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
Copy link

scottfr commented Feb 26, 2017

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
Copy link

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

@scottfr
Copy link

scottfr commented Sep 29, 2017

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

@schabluk
Copy link

schabluk commented Oct 6, 2017

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: react-dnd/react-dnd#858.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants