bevacqua / react-dragula

:ok_hand: Drag and drop so simple it hurts
http://bevacqua.github.io/react-dragula
MIT License
994 stars 77 forks source link

Accessing Child Items in dragula callbacks #2

Open seanoshea opened 9 years ago

seanoshea commented 9 years ago

Hi there,

I'm struggling to understand the best way to map the dom elements passed back in dragula callbacks to react child items. My code is as follows:

    componentDidMount: function () {
      var container = React.findDOMNode(this),
      drake = ReactDragula([container], {
        moves: function (el, source, handle, sibling) {
          // there are some items in the list of children associated with this container
          // which should not be draggable. Identifying these by their class name feels
          // somewhat wrong (shouldnt be reaching into the DOM to understand a child's state?).
          return el.className !== 'draggable';
        },
        direction: 'horizontal'
      });
      drake.on('drop', (el, target, source, sibling) => {
        // how to I convert the DOM `el` here into the corresponding child item
        this.props.moveFrameCallback(item.id);
      });
    }

The el parameter passed into the drop method is a dom child element of the dnd container. Was wondering what's the best way to map this dom element to the react child item so I can invoke a callback?

I'd like to be able to make an API call based on the drop action and need the id of the child element. The id of the child item is somewhat parsable in the data-reactid attribute of the dom node - is that where I should be taking it from, or is there a more advisable way?

Thanks again for dragula,

Sean

evandavis commented 9 years ago

It appears that dragula tracks DOM elements instead of React components, but that doesn't make sense in a React app as you never really care about the DOM. :(

seanoshea commented 9 years ago

Yep - after reading some react documentation and reading this SO post , it appears that a mapping between dom nodes and react components isn't exact the react way of doing things.

In order for this to work, some the corresponding react component would need to be sent back in line 266 of dragula.js:

 else {
      drake.emit('drop', item, target, _source, _currentSibling);
    }

Based on this article, I think there'd (very understandably) be some resistance to leaking any react specific code into dragula.js to provide this react component in the callback.

@evandavis @bevacqua - Would there be any any way for react-dragula to accommodate this additional context?

bevacqua commented 9 years ago

Can't we just map the drake instance to the react component?

evandavis commented 9 years ago

@bevacqua how do you propose doing that?

bevacqua commented 9 years ago

I haven't used React that much, but we could change react-dragula to fit React -- as long as dragula itself doesn't need to change to accomodate React we're fine. So, maybe we could do

In react-dragula:

drake.on('react-component', component => _component = component);

In user code:

drake.emit('react-component', component);
3Cbwaltz commented 8 years ago

Where did we land with this? I am running into this problem now.

ch2ch3 commented 8 years ago

+1

I'm currently getting around this by assigning data-* attributes to the DOM elements, but would much prefer if there was another way :)

levrik commented 8 years ago

In the next version of React the data-reactid's will be removed, so you shouldn't try to map them to React components.

avk commented 8 years ago

Am I missing something? What's the point of react-dragula if it breaks how React works with the DOM?

SeanRoberts commented 8 years ago

I'm also unclear on how this project actually lets you use dragging and dropping to accomplish anything. Dragula is a very nice and lightweight project, it would be great to use this, but I'll check out http://gaearon.github.io/react-dnd/ for now.

tnrich commented 8 years ago

Hey @bevacqua , is there any solution to this issue? It seems like we need some sort of callback like "onDrop" that includes info about the element being dragged.

tnrich commented 8 years ago

... Does anyone have a solution or workaround to this issue?

avk commented 8 years ago

Given that my question was never addressed and this still seems to be antithetical to how React works by changing the DOM directly, I've abandoned this for http://gaearon.github.io/react-dnd/ as well.

rohan-deshpande commented 8 years ago

I'm not seeing why using data attributes is so bad? I'm not seeing anything break. Take this example:

var listsNode = ReactDOM.findDOMNode(this.refs.lists);

drake.on('drop', function (el, target, source, sibling) {
    var listsNum = source.children.length;
    var i, j;

    for (i = 0; i < listsNum; i++) {
        console.log(source.children[i].dataset.oid);
    }

    for (j = 0; j < listsNum; j++) {
        console.log(listsNode.children[j].dataset.oid);
    }
});

In both instances the correct oid is logged. Data attributes aren't somehow "not React", they are valid HTML5 attributes and work fine with React (https://facebook.github.io/react/docs/jsx-gotchas.html#custom-html-attributes).

So what's wrong with using this method to update the order? @levrik We are not talking about the react- attributes, we are talking about custom html5 data attributes.

Seems like an easy and valid way to fix the problem to me.

paddotk commented 5 years ago

Why is it not ok to read the DOM? Seems to me that accessing elements through data-something attributes does the same thing.