Search code examples
htmljquery-uijquery-ui-droppable

jQuery UI Droppable - How to actually change the HTML?


Using jQuery UI's Droppable I have made a shelf type thing where the items contained on it can be moved. Here's the code: http://jsfiddle.net/JoeyMorani/7LWj4/

Is it possible to actually change the HTML of the shelf, so when the '.boxArt' divs are moved, they are also moved in the HTML. At the moment it seems to only change the position of the div and not actually move it.

I want to do this so I can detect where the divs are. (What their parent div is)

Thanks for the help! :)


Solution

  • I made some changes to the HTML and CSS from your demo but I have something working. The HTML is simpler and has not affected the result, although if you need the previous layout my answer might not be totally right for you.

    The full code is duplicated below as well as in a jsFddle demo. The code actually becomes a lot simpler after detaching the .boxArt and moving it in the DOM, since the animation just needs to change the top and left back to 0. The only difficult part was calculating the correct position to set the .boxArt to before animating. This is due to the draggable being relatively positioned to the element it was dragged from. As soon as it is moved in the DOM, this position is now completely incorrect. So the code works out and sets the draggable relative position to the new parent first (after moving it in the DOM) and then animates back to top:0,left:0.

    This is working for me in Chrome but I have not tested in any other browsers. console.log left in to show what's going on.

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <title>title</title>
        <style type="text/css">
          .shelfRow {
            width:1865px;
            height:280px;
          }
          #shelves {
            position:relative;
            width:950px;
            height:566px;
            background:#CCC;
            border:1px solid #333;
            overflow-y:hidden;
            overflow-x:auto;
          }
          .drop {
            width:155px;
            height:200px;
            padding:2px;
            margin-top:30px;
            margin-left:25px;
            float:left;
            position:relative;
          }
          .dropHover {
            padding:0px;
            border:2px solid #0C5F8B;
            -webkit-box-shadow: 0 0 3px 1px #0C5F8B;
            box-shadow: 0 0 3px 1px #0C5F8B;
            -moz-box-shadow: 0 0 20px #0C5F8B;
          }
          .boxArt {
            width:155px;
            height:200px;
            -webkit-box-shadow: 0 0 8px 1px #1F1F1F;
            box-shadow: 0 0 8px 1px #1F1F1F;
            -moz-box-shadow: 0 0 20px #1F1F1F;
            color:#000;
            background:#FFF;
          }
        </style>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/jquery-ui.min.js"></script>
        <script type="text/javascript">
          $(function() {
              var shelfOffset = $('#shelves').offset();
              var dropMarginTop = parseInt($('.drop').css('marginTop'));
              var dropMarginLeft = parseInt($('.drop').css('marginLeft'));
    
              $('.drop').droppable({
                  accept: function(el) {
                    return $(this).children('.boxArt').length === 0 && el.hasClass('boxArt');
                  },
                  tolerance: 'intersect',
                  hoverClass: 'dropHover',
                  drop: function(event, ui) {
                    ui.draggable.detach().appendTo($(this));
    
                    var originalOffset = ui.draggable.data('originalOffset');
                    console.log('originalOffset', originalOffset.top, originalOffset.left);
    
                    var boxArt = $(this).children('div');
                    var boxPosition = boxArt.position();
                    console.log('boxArt position', boxPosition.top, boxPosition.left);
    
                    var container = $(this);
                    var containerPosition = container.position();
                    console.log(container, containerPosition.top, containerPosition.left);
    
                    var newTop = originalOffset.top + boxPosition.top - containerPosition.top - shelfOffset.top - dropMarginTop;
                    var newLeft = originalOffset.left + boxPosition.left - containerPosition.left - shelfOffset.left - dropMarginLeft;
    
                    console.log('new offset', newTop, newLeft);
                    boxArt.css({top:newTop,left:newLeft}).animate({top:0,left:0});
                  }
              });
    
              $('.boxArt').draggable({
                start: function(event, ui) {
                  $(this).data('originalOffset', ui.offset);
                },
                revert: 'invalid'
              });
          });
        </script>
      </head>
      <body>
        <div id="shelves">
          <div class="shelfRow">
            <div class="drop"></div>
            <div class="drop"><div class="boxArt" id="boxArt2">2</div></div>
            <div class="drop"></div>
            <div class="drop"></div>
            <div class="drop"></div>
            <div class="drop"></div>
            <div class="drop"></div>
            <div class="drop"></div>
            <div class="drop"></div>
            <div id="drop15"></div>
          </div>
          <div class="shelfRow">
            <div class="drop"><div class="boxArt" id="boxArt1">1</div></div>
            <div class="drop"></div>
            <div class="drop"></div>
            <div class="drop"></div>
            <div class="drop"></div>
            <div class="drop"></div>
            <div class="drop"></div>
            <div class="drop"></div>
            <div class="drop"></div>
            <div class="drop"></div>
          </div>
        </div>
      </body>
    </html>