1
votes

I'm trying to use HTML5 drag and drop in my website. dragstart and dragend are fired, but dragenter, dragleave, dragover, and drop don't work until I refresh the page.

drag and drop problem

The node from the tree in the sidebar should be able to drag to the cell in the table. The tree is made with jsTree. I've tried it with Firefox, Chrome, and IE. They all have the same behavior.

Sidebar tree (rhtml file)

<section id="navbar-jstree">
</section>

<script>
  $(function () {
    $('#navbar-jstree')
      .on('select_node.jstree', loadDetails)
      .on('after_open.jstree', addAttributes)
      .jstree({ 
      'core' : {
        'data' : { 
          'url' : function (node) {
            return node.id === '#' ?
              '/nav_trees.json' :
              '/nav_trees/' + node.id + '.json';
          },
          'data' : function (node) {
            return {'id': node.id};
          }
        },
        'themes' : {"dots" : false}
      },
      'plugins' : ['types'] 
    });
    
    function addAttributes(e, data) {
      $('#' + data.node.id + ' ul > li').each(function(idx, elem) {
        var node = $(elem);
        var node_id = node.attr('id') % 1e8;
        if (isItem(node_id)) {
          node
            .attr('draggable', 'true')
            .on('dragstart', function(e){
              $(this).addClass('dragged');
              e.originalEvent.dataTransfer.effectAllowed = 'copy';
              var nodeData = { name: $(this).text(), id: $(this).attr('id') };
              e.originalEvent.dataTransfer.setData('text/plain', JSON.stringify(nodeData));
          }).on('dragend', function(e) {
              $(this).removeClass('dragged');
          });
        }
      });
    }
  });
</script>

Drop action code (coffeescript file)

$ ->
    $.event.props.push 'dataTransfer'
    
    handleDragEnter = -> $(this).addClass 'droppable'
    handleDragLeave = -> $(this).removeClass 'droppable'
    handleDragOver = (e) ->
        e.preventDefault()
        e.originalEvent.dataTransfer.dropEffect = 'copy'
        false
    handleDrop = (e) ->
        e.stopPropagation()
        e.preventDefault()
        $(this).removeClass 'droppable'
        nodeDataStr = e.dataTransfer.getData 'text/plain'
        nodeData = JSON.parse nodeDataStr
        column = $(this).index() + 1
        data =
            text: nodeData.name
            node_id: nodeData.id
            start: $('.scheduler .th:nth-child(' + column + ')').text()
            user_id: $(this).parents('.scheduler-row').prev().data('id')
        $.post '/events', data
        false
    
    $('.scheduler-row td')
        .on('dragenter', handleDragEnter)
        .on('dragover', handleDragOver)
        .on('dragleave', handleDragLeave)
        .on('drop', handleDrop)

Table (page source)

<div class="scheduler table">
    <div class="thead">
      <div class="tr">
        <div class="th">2014-06-09</div>
        <div class="th">2014-06-16</div>
        <div class="th">2014-06-23</div>
        <div class="th">2014-06-30</div>
        <div class="th">2014-07-07</div>
        <div class="th">2014-07-14</div>
        <div class="th">2014-07-21</div>
      </div>
    </div>
    <table cellspacing="0">
      <tbody>
        <tr>
          <th scope="row" data-id="1">Eva Ogbe</th>
          <td class="scheduler-row">
            <table class="table" cellspacing="0">
              <tbody>
                <tr>
                  <td class=""></td><td></td><td></td><td></td><td></td><td></td><td></td>
                </tr>
              </tbody>
            </table>
          </td>
        </tr>
      </tbody>
    </table>
  </div>

I tried to do a fiddle, but that works fine.

How do I get the drop action to work without needed to refresh?

1

1 Answers

1
votes

Did some more digging. Turns out the problem was with my coffeescript not loading due to turbolinks. The solution is to bind the document ready event to page change like so:

ready = ->
    $.event.props.push 'dataTransfer'
    # ...snip remainder of function...

$(document).on 'page:change', ready