A. Wheatman
A. Wheatman

Reputation: 6396

Hidden droppables doesn't trigger over and out even after it becomes visible

I would like to have top level droppable area and when the user start to drag some elements into this area, I want to split it on different sections (north, east, south and west etc.) and allow the user to drop at any of them.

what would be the best way to do this?

here is what I try to do:

HTML

<div class='main_droppable_area'>
    <div class='drop_area north'></div>
    <div class='drop_area east'></div>
    <div class='drop_area south'></div>
    <div class='drop_area west'></div>
</div>
<div class='draggable_area'>
</div>

CSS

.main_droppable_area {
    top: 50px;
    left: 50px;
    right: 50px;
    height: 200px;
    border: 1px dashed blue;
    position: absolute;
}

.drop_area {
    position: absolute;
    border: 1px dashed blue;
    background-color: #eff;
    opacity: 0.5;
    filter: alpha(opacity=50);
    display: none;
}

.drop_area.active {
    opacity: 1;
    filter: alpha(opacity=100);
}

.drop_area.north {
    top: 0px;
    left: 0px;
    right: 0px;
    height: 50px;
}

.drop_area.south {
    bottom: 0px;
    left: 0px;
    right: 0px;
    height: 50px;
}

.drop_area.west {
    top: 50px;
    left: 0px;
    bottom: 50px;
    width: 50px;
}

.drop_area.east {
    top: 50px;
    right: 0px;
    bottom: 50px;
    width: 50px;
}

.draggable_area {
    position: absolute;
    top: 300px;
    left: 50px;
    background-color: blue;
    width: 50px;
    height: 50px;
}

JavaScript

$(document).ready(function() {
    $( '.draggable_area' ).draggable();

    $('.main_droppable_area').droppable({
        accept: '.draggable_area',
        over: function() {
            console.log('main_droppable_area - over');
            $('.drop_area').show();
        },
        out: function() {
            console.log('main_droppable_area - out');
            $('.drop_area').hide();
        }
    });

    $('.drop_area').droppable({
        accept: '.draggable_area',
        over: function() {
            $(this).addClass('active');
            console.log('drop_area - over');
        },
        out: function() {
            $(this).removeClass('active');
            console.log('drop_area - out');
        }
    });
});

But unfortunately this code doesn't work all the time... for example it doesn't work if I try to drag item from outside the main droppable area.

However if I drag and drop the item into that area and start to drag it again it works.

Is something wrong with my code? here is my JSFiddle example

UPDATE

Thanks to T J for the solution... here is JS fiddle with the working example

Upvotes: 2

Views: 119

Answers (1)

T J
T J

Reputation: 43166

If you hide the droppables using display:none, the element won't be rendered at all. Hence when a valid draggable starts dragging, it won't be activated, and the changes you make won't take place until a new drag is started activating the droppables.

One work around is to use visibility:hidden instead to hide your inner draggables so that the elements will be rendered, and dragging will activate droppables so that over, out etc function properly.

$(document).ready(function() {
  $('.draggable_area').draggable();

  $('.main_droppable_area').droppable({
    accept: '.draggable_area',
    over: function() {
      console.log('main_droppable_area - over');
      $('.drop_area').removeClass("invisible");
    },
    out: function() {
      console.log('main_droppable_area - out');
      $('.drop_area').addClass("invisible");
    }
  });

  $('.drop_area').droppable({
    activate: function() {
      console.log("activated");
    },
    accept: '.draggable_area',
    over: function() {
      $(this).addClass('active');
      console.log('drop_area - over');
    },
    out: function() {
      $(this).removeClass('active');
      console.log('drop_area - out');
    }
  });
});
.main_droppable_area {
  position: absolute;
  top: 50px;
  left: 50px;
  right: 50px;
  height: 200px;
  border: 1px dashed blue;
}
.drop_area {
  position: absolute;
  border: 1px dashed blue;
  background-color: #eff;
  opacity: 0.5;
  filter: alpha(opacity=50);
}
.drop_area.active {
  opacity: 1;
  filter: alpha(opacity=100);
}
.drop_area.north {
  top: 0px;
  left: 0px;
  right: 0px;
  height: 50px;
}
.drop_area.south {
  bottom: 0px;
  left: 0px;
  right: 0px;
  height: 50px;
}
.drop_area.west {
  top: 50px;
  left: 0px;
  bottom: 50px;
  width: 50px;
}
.drop_area.east {
  top: 50px;
  right: 0px;
  bottom: 50px;
  width: 50px;
}
.draggable_area {
  position: absolute;
  top: 300px;
  left: 50px;
  background-color: blue;
  width: 50px;
  height: 50px;
}
.invisible {
  visibility: hidden;
}
<link href="http://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>
<div class='main_droppable_area'>
  <div class='drop_area north invisible'></div>
  <div class='drop_area east invisible'></div>
  <div class='drop_area south invisible'></div>
  <div class='drop_area west invisible'></div>
</div>
<div class='draggable_area'></div>

Upvotes: 2

Related Questions