Question

I am trying to implement drag-n-drop to change dates in an article scheduling system. I want the user to be able to drag an article entry from one date to another, and the schedules should then automatically be updated. Here is my code:

<script type="text/javascript">
    $(function () {
        $(".scheduledArticleRow").draggable({
            cursor: "move",
            cursorAt: { top: -12, left: -20 },
            opacity: 0.5,
            helper: function (event) {
                return $("<div class='ui-widget-header'>" + $(this).data('title') + "</div>")
            }
        });
        $(".articleNeededRow").droppable();
        $(".reservedDateRow").droppable();

        $(".scheduledArticleRow").off("dragstart").on("dragstart", function (e) {
            console.log("dragstart");
            e.dataTransfer.setData("articleId", $(this).data("articleId"));    // Uncaught TypeError: Cannot call method 'setData' of undefined 
            e.dataTransfer.setData("oldDate", $(this).data("date"));        // Uncaught TypeError: Cannot call method 'setData' of undefined
            e.originalEvent.dataTransfer.setData("articleId", $(this).data("articleId"));    // Uncaught TypeError: Cannot call method 'setData' of undefined 
            e.originalEvent.dataTransfer.setData("oldDate", $(this).data("date"));            // Uncaught TypeError: Cannot call method 'setData' of undefined
        });
        $(".articleNeededRow").off("drop").on('drop', function (e) {
            console.log("drop");
            e.preventDefault();
            e.stopPropagation();
            changeScheduledDate(e);
        });
        $(".reservedDateRow").off("drop").on('drop', function (e) {
            console.log("drop");
            e.preventDefault();
            e.stopPropagation();
            changeScheduledDate(e);
        });
    });

    function changeScheduledDate(e) {
        debugger;
        var articleId = e.dataTransfer.getData("articleId");    // Uncaught TypeError: Cannot call method 'setData' of undefined 
        var oldDate = e.dataTransfer.getData("oldDate");        // Uncaught TypeError: Cannot call method 'setData' of undefined
        articleId = e.originalEvent.dataTransfer.getData("articleId", $(this).data("articleId"));    // Uncaught TypeError: Cannot call method 'setData' of undefined 
        oldDate = e.originalEvent.dataTransfer.getData("oldDate", $(this).data("date"));            // Uncaught TypeError: Cannot call method 'setData' of undefined

        var newDate = $(this).parents(".tr").data("date");

        // Do date-change stuff
    }


</script>

<div class="table tidytable" width="90%">
    <div class="thead">
        <div class="cell">Date</div>
        <div class="cell">Article title</div>
    </div>
    <div class="tbody" id="scheduleBody">
        <div class="tr articleNeededRow" data-date="2014-02-11">
            <div class="cell"><strong>Tue, 11th Feb</strong></div>
            <div class="cell articleNeeded">Article needed.</div>
        </div>
        <div class="tr articleNeededRow" data-date="2014-02-12">
            <div class="cell"><strong>Wed, 12th Feb</strong></div>
            <div class="cell articleNeeded">Article needed.</div>
        </div>
        <div class="tr reservedDateRow" data-date="2014-02-13">
            <div class="cell"><strong>Thu, 13th Feb</strong></div>
            <div class="cell articleNeeded"><strong>Reserved for an upcoming article.</strong></div>
        </div>
        <div class="tr scheduledArticleRow" data-date="2014-02-14" data-articleid="8789" data-title="This is the title"
            draggable="true">
            <div class="cell"><strong>Fri, 14th Feb</strong></div>
            <div class="cell">
                <h3>This is the title</h3>
            </div>
        </div>
    </div>
</div>

I am using a .css table. The user should be able to drag from anywhere in the "This is the title" row to any of the other rows. But in the dragStart event handler, e.dataTransfer is set to null and it is impossible to pass any data across to the drop event. I don't want to resort to a cookie, HTML5 Local Storage or a global variable - this thing should just work. I have it drag-n-drop using dataTransfer working nicely in other parts of the application. Some posts recommend that I need to use e.originalEvent.dataTransfer, but that is also null. I am using Google Chrome BTW. I have created a jsFiddle - http://jsfiddle.net/btA97/ - any help greatly appreciated.

Was it helpful?

Solution

It seems that your .draggable() is doing something wrong. You also need to do e.preventDefault() and e.stopPropagation() in dragover to make sure drop occurs.

This code gets to all the events correctly:

   $(function () {
       /*
       $(".scheduledArticleRow").draggable({
           cursor: "move",
           cursorAt: {
               top: -12,
               left: -20
           },
           opacity: 0.5,
           helper: function (event) {
               return $("<div class='ui-widget-header'>" + $(this).data('title') + "</div>")
           }
       });
        */

       $(".articleNeededRow").droppable(); // With this commented out the code still works
       $(".reservedDateRow").droppable(); // This one too

       $(".scheduledArticleRow").on("dragstart", function (e) {
           console.log("dragstart");
           console.dir(e);
           e.originalEvent.dataTransfer.setData("articleId", $(this).data("articleId"))
           e.originalEvent.dataTransfer.setData("oldDate", $(this).data("date"));
       });
       $(".articleNeededRow").on('dragover', function (e) {
           console.log("dragover");
           e.preventDefault();
           e.stopPropagation();
       });
       $(".articleNeededRow").on('drop', function (e) {
           console.log("drop");
           e.preventDefault();
           e.stopPropagation();
           changeScheduledDate(e);
       });
       $(".reservedDateRow").on('dragover', function (e) {
           console.log("dragover");
           e.preventDefault();
           e.stopPropagation();
       });
       $(".reservedDateRow").on('drop', function (e) {
           console.log("drop");
           e.preventDefault();
           e.stopPropagation();
           changeScheduledDate(e);
       });
   });

   function changeScheduledDate(e) {
       articleId = e.originalEvent.dataTransfer.getData("articleId");
       oldDate = e.originalEvent.dataTransfer.getData("oldDate");
       console.log("articleID: "+articleId);
       console.log("oldDate: "+oldDate);

       var newDate = $(this).parents(".tr").data("date");
       console.log("newDate: "+newDate);

       // Do date-change stuff
   }

OTHER TIPS

Needed to use the event.originalEvent object.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top