Why won't "draggable = 'true'" work on React rendered component?

12,080

Solution 1

It should work, but you probably want to implement onDragOver event(s) too. Otherwise it will look like it doesn't work because you can drag your component, but don't have any legal place to drop it. onDragOver lets you specify if an element accepts dropping and which elements it accepts.

As you can see in the fiddle you linked there are onDragOver events which look something like this

onDragOver: function(e) {
    e.preventDefault();
    // Logic here
}

Calling e.preventDefault(); tells the browser that dropping is possible here. You can put the onDragOver event on any of your parent elements, or on the tr itself. You can read more about drop targets here. If you remove the onDragOver event from the jsFiddle you linked the code in the fiddle stops functioning too.

If you implement onDragOver you will be able to implement an onDrop event on your table that handles dropped tr elements.

Here is your code with the events implemented:

var Vehicle = React.createClass({
    onDragOver: function(e) {
      e.preventDefault();
      // Logic here
      console.log('onDragOver');
    },
    onDragStart: function(e){
        e.dataTransfer.setData('id', 'setTheId');
        console.log('onDragStart');
    },
    onDrop: function(e) {
        console.log('onDrop');
        var id = event.dataTransfer.getData('id');
        console.log('Dropped with id:', id);
    },
    render: function() {
        that = this;
        var loads = this.props.truck.map(function(load , i){
            load.truckid = i
            return (

                    <tr key={i} draggable="true" onDragOver={that.onDragOver} onDragStart={that.onDragStart}>
                        <td>
                            {load.load_number}
                        </td>
                        <td>
                            {load.stops[0].location_name}
                        </td>
                        <td>
                            {load.stops[1].location_name}
                        </td>
                    </tr>

            )
        })
        return (
                <div>
                    <div className="panel-body" >
                        <table className="table" onDrop={this.onDrop}>
                            <tbody>
                                {loads}
                            </tbody>
                        </table>
                    </div>
                </div>
        )
    } 
});

Here is a jsFiddle of this: http://jsfiddle.net/kb3gN/10761/

Solution 2

The reason that the item doesn't seem to drag is you have e.preventDefault(); inside onDragStart function, which prevents it from showing the default dragging movement. Just remove that line, so it would look like this and it should work:

var Vehicle = React.createClass({
  ...
  onDragStart: function(e){
    // REMOVED THIS LINE
    //e.preventDefault();

    console.log('ondragstart');
  },
  ...
Share:
12,080
Shane Davis
Author by

Shane Davis

Crypto and design. #webdesign #solidity #javascript #react #hardhat #truffle #swift #kotlin #webflow

Updated on June 05, 2022

Comments

  • Shane Davis
    Shane Davis almost 2 years

    this is driving me mad and hope someone might be able to help.

    I have this React.Component:

    var Vehicle = React.createClass({
        ondragend: function(e) {
          e.preventDefault();
          // Logic here
            console.log('onDragOver');
        },
        ondragstart: function(e){
          e.preventDefault();
          console.log('ondragstart');
        },
        render: function() {
        that = this
        var loads = this.props.truck.map(function(load , i){
            load.truckid = i
            return (
                    <tr key={i} draggable="true" dragstart={that.ondragstart} dragend={that.ondragend}>
                        <td>
                            {load.load_number}
                        </td>
                        <td>
                            {load.stops[0].location_name}
                        </td>
                        <td>
                            {load.stops[1].location_name}
                        </td>
                    </tr>
            )
        })
        return (
                <div className="panel panel-primary" draggable="true">
                    <VehiclePanelHeading vehicleNbr={this.props.vehicleNbr}></VehiclePanelHeading>
                    <div className="panel-body" >
                        <table className="table">
                            <tbody>
                                {loads}
                            </tbody>
                        </table>
                    </div>
                </div>
        )
    

    } });

    As you can see, I am trying to make the s draggable. Unfortunetly, this won't work, even if I use the Chrome dev tools to manually add this into the html in the browser.

    I have tried removing my link to Bootstrap incase this is something to do with the CSS rules, and also tried to render just a html table with no dynamic values.

    I can't see how the code in this fiddle:

    jsFiddle

    Works by setting the draggable=true in the render function, but mine won't.

    Thanks in advance for any help.

    Edit Added the dropEnd/Start handlers but no change.

    Curiously, if I add draggable=true to the div.panel container, this is draggable whilst the containing s remain not.

    top level container is draggable

    Update

    If I create a quick .html page with this table:

                           <table className="table">
                            <thead>
                                <tr>
                                    <td>Name</td>
                                    <td>Tangyness</td>
                                </tr>
                            </thead>
                            <tbody>
                                <tr draggable="true">
                                    <td>Apple</td>
                                    <td>4</td>
                                </tr>
                                <tr draggable="true">
                                    <td>Orange</td>
                                    <td>7</td>
                                </tr>
                            </tbody>
                        </table>
    

    Then the desired draggble = true works on the table rows. However, if I paste this into the React render function:

            return (
                <div className="panel panel-primary" >
                    <VehiclePanelHeading vehicleNbr={this.props.vehicleNbr}></VehiclePanelHeading>
                    <div className="panel-body" >
                        <table className="table">
                            <thead>
                                <tr>
                                    <td>Name</td>
                                    <td>Tangyness</td>
                                </tr>
                            </thead>
                            <tbody>
                                <tr draggable="true">
                                    <td>Apple</td>
                                    <td>4</td>
                                </tr>
                                <tr draggable="true">
                                    <td>Orange</td>
                                    <td>7</td>
                                </tr>
                            </tbody>
                        </table>
                    </div>
                </div>
        )
    

    Then suddenly, the 'draggability' is lost.

  • Shane Davis
    Shane Davis about 9 years
    Thanks for the quick reply! I implemented the changes as per the edit above but no change. Curiously, the parent div.panel does respond to the draggable=true - from this I am assuming that this isn't anything to do with Reacts shadow div or the availablity of the node on render.
  • Shane Davis
    Shane Davis about 9 years
    Excellent! thank you. Once last thing: do you know why the dragElement does not appear when dragging? ie the placeholder? After implementing your code changes I am now following along this post: webcloud.se/sortable-list-component-react-js in the gist with this, the element stayed visible on dragging - mine disappear.
  • AndersNS
    AndersNS about 9 years
    I don't know that sorry. The placeholder appears with divs, images, list items, etc. Maybe something to with tables.