Containment issue with draggable element within a resizable container

1.1k Views Asked by At

I thought this would be simple but there appears to be a few bugs in jQuery UI when placing a draggable element within a resizable container.

The following code allows the draggable element to be placed slightly outside the container because of the extra height created by the resize handle (jsfiddle here).

HTML

<div class="container2">
    <div class="item2"></div>
</div>

CSS

.container2 {
    min-width:300px;
    min-height:200px;
    outline:1px solid black;
}
.item2 {
    width:50px;
    height:50px;
    background-color:red;
}

jQuery

$(".container2").resizable();

$(".item2").draggable({
    containment: ".container2"
}).resizable({
    containment: ".container2"
});

So I got around this by setting the containment as the coordinates of the container using the following code:

$(".item2").draggable({
    start: function (event, ui) {
        var containmentX1 = $(".container2").offset().left;
        var containmentY1 = $(".container2").offset().top;
        var containmentX2 = ($(".container2").outerWidth() + $(".container2").offset().left - $(this).outerWidth())
        var containmentY2 = ($(".container2").outerHeight() + $(".container2").offset().top - $(this).outerHeight())
        $(this).draggable({
            containment: [containmentX1, containmentY1, containmentX2, containmentY2]
        });
    },
}).resizable({
    containment: ".container2"
});

This works fine except for one problem... the containment coordinates are only set the second time the draggable element is moved.

I used create rather than start to get around this, but then the coordinates are not changed if the container is resized.

Is there a way to get the coordinates recognised as the containment area on first drag.?

2

There are 2 best solutions below

0
On BEST ANSWER

you can wrap your containment recalculation into a separate function and call it after initializing draggable (on create) and each time container gets resized (om stop)

$(".container2").resizable({
stop: reCalcBounds
});

$(".item2").draggable({
    create: reCalcBounds
}).resizable({
    containment: ".container2"    
});

function reCalcBounds(){
 var $item =  $(".item2");
 $container = $(".container2");
 var containmentX1 = $container.offset().left;
    var containmentY1 = $container.offset().top;
    var containmentX2 = ($container.outerWidth() + $container.offset().left - $item.outerWidth())
    var containmentY2 = ($container.outerHeight() + $container.offset().top -$item.outerHeight())
    $item.draggable("option", "containment", [containmentX1, containmentY1, containmentX2, containmentY2]);

}

see updated fiddle

I think you also need to take care of changing minWidth and minHeight of the resizable container depending on position of the draggable item, you can use "stop" callaback of the draggable for that

0
On

if following your approach you can set containment when resizing '.container2' and when initializing look there

Another solution could be just to use css:

 .container2 .ui-resizable-s
{
    bottom:0;
}
.container2 .ui-resizable-e
{
    right:0;
}

you can verify there , hope this helps