Search code examples
javascriptjqueryjquery-uijquery-ui-draggablejquery-ui-droppable

Highlighting only the droppable which is hovered or to which item is dropped


What I'd like to do is to set border color to blue for .droparea element that contains an .item element.

Also there is also a hover effect for the .droparea which changes the border color to blue.

So if I move the .item element to another .droparea it should automatically change border color for the current .droparea to blue and change the border of previously used .droparea to default color (black).

$(document).ready(function() {
  $(".item").draggable({
    scroll: false,
    revert: 'invalid',
    stack: false,
    create: function() {
      $(this).data('position', $(this).position())
    },
    cursor: "pointer",
    start: function() {
      $(this).stop(true, true)
    },
    drag: function(event, ui) {
      $(".droparea").removeClass("highlight");
    }
  });
  $(".droparea").droppable({
    accept: ".item",
    drop: function(event, ui) {
      $(this).addClass("highlight").find("p");
      snapToMiddle(ui.draggable, $(this));
    }
  });
});

function snapToMiddle(dragger, target) {
  var topMove = target.position().top - dragger.data('position').top + (target.outerHeight(true) - dragger.outerHeight(true)) / 2;
  var leftMove = target.position().left - dragger.data('position').left + (target.outerWidth(true) - dragger.outerWidth(true)) / 2;
  dragger.animate({
    top: topMove,
    left: leftMove
  }, {
    duration: 200,
    easing: 'linear'
  });
}
.item {
  position: relative;
  margin: 0 auto;
  width: 100px;
  height: 100px;
  border: 1px solid red;
}
.droparea {
  width: 150px;
  height: 150px;
  float: left;
  margin: 2px;
  border: 1px solid #000;
  outline: 1px solid transparent
}
.highlight {
  border: 1px solid blue
}
.droparea:hover {
  border: 1px solid blue
}
<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.js"></script>

<div class="droparea">
  <div class="item"></div>
</div>


<div class="droparea"></div>
<div class="droparea"></div>


Solution

  • Few things to note here:

    • jQuery UI draggable only adjusts the style of an element, It does not alter its position in DOM, So the .item will always be the child of first draggable, and since you've specified the CSS :hoverpseudo selector - .droparea:hover, You'll always be hovering the first droppable while dragging since you're hovering it's child.
    • We can fix this issue by setting highlight class on hover using the hoverClass option of draggable, but since you're removing the highlight during drag event, the class set on hover will be immediately removed. So we should not remove the class on drag.
    • Finally, You can use jQuery UI's position() utility method for center aligning the item on drop.

    So you can achieve what you're trying to as following:

    $(document).ready(function() {
      $(".item").draggable({
        scroll: false,
        revert: 'invalid',
        stack: false,
        cursor: "pointer",
      });
      $(".droparea").droppable({
        accept: ".item",
        hoverClass: "highlight",
        drop: function(event, ui) {
          var $this = $(this);
          $(".highlight").removeClass("highlight");
          $this.addClass("highlight");
          ui.draggable.position({
            my: "center",
            at: "center",
            of: $this,
            using: function(pos) {
              $(this).animate(pos, 200, "linear");
            }
          });
        }
      });
    });
    .item {
      position: relative;
      margin: 0 auto;
      width: 100px;
      height: 100px;
      border: 1px solid red;
    }
    .droparea {
      width: 150px;
      height: 150px;
      float: left;
      margin: 2px;
      border: 1px solid #000;
      outline: 1px solid transparent
    }
    .highlight {
      border: 1px solid blue
    }
    <script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.js"></script>
    
    <div class="droparea">
      <div class="item"></div>
    </div>
    
    <div class="droparea"></div>
    <div class="droparea"></div>


    Also, I've to warn you that jQuery UI and CSS float have a bad history, which is evident if you visit bugs.jqueryui.com. You're better of using display:inline-block for this purpose, you can even avoid speciying margin manually.