Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery UI sortable placeholder with Bootstrap rows

I'm trying to make a draggable set of panels using jQuery UI and Bootstrap rows/panels. I've got something which mostly works, my problem is that the placeholder isn't sized correctly when you drag the panel. It's the size of the entire row instead of the size of the element.

$('.row').sortable({
	connectWith: ".panel",
	handle: ".panel-heading",
	placeholder: "panel-placeholder"
});

$('.panel').on('mousedown', function(){
	$(this).css( 'cursor', 'move' );
}).on('mouseup', function(){
	$(this).css( 'cursor', 'auto' );
});;
.panel-placeholder {
	border: 1px dotted black;
	margin: 1em 1em 1em 1em;
	height: 50px;
}
<script src="https://code.jquery.com/jquery-3.0.0.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet"/>
<div class="container-fluid">
	<div class="row">
		<div class="col-md-3">
			<div class="panel panel-primary">
				<div class="panel-heading">
					<h3 class="panel-title">Panel title</h3>
				</div>
				<div class="panel-body">
					Panel content
				</div>
			</div>
		</div>
		<div class="col-md-4">
			<div class="panel panel-primary">
				<div class="panel-heading">
					<h3 class="panel-title">Panel title</h3>
				</div>
				<div class="panel-body">
					Panel content
				</div>
			</div>
		</div>
		<div class="col-md-8">
			<div class="panel panel-primary">
				<div class="panel-heading">
					<h3 class="panel-title">Panel title</h3>
				</div>
				<div class="panel-body">
					Panel content
				</div>
			</div>
		</div>
	</div>
</div>
$('.col-md-4').sortable({
    connectWith: ".col-md-4",
    handle: ".panel-heading",
    placeholder: "panel-placeholder"
});

JSFiddle: https://jsfiddle.net/zdfb3e0p/8/

Any ideas?

like image 798
Bravo Delta Avatar asked Aug 12 '16 16:08

Bravo Delta


3 Answers

If you wish your placeholder to have the item's exact dimensions, you can use the Sortable start event, as described in the API, to compute and affect the same styling as dragging starts.

Once you have the reference of both the placeholder element, as well as the handle element from the event, you can just copy each relevant CSS attribute.

In addition, in order to maintain the positioning in the grid as the original element, you will have to make sure to assign the proper col class from the original element. I also accounted for some quirks, like the fact that by default the jQuery placeholder is assigned an inline margin, and that the dashed border also takes up some space.

$('.row').sortable({
    connectWith: ".panel",
    handle: ".panel-heading",
    placeholder: "panel-placeholder",
    start: function(event, ui){
        var classes = ui.item.attr('class').split(/\s+/);
        for(var x=0; x<classes.length;x++){   
            if (classes[x].indexOf("col")>-1){
            ui.placeholder.addClass(classes[x]);
           }
         }

        ui.placeholder.css({      
          width: ui.item.innerWidth() - 30 + 1, //account for margin and border
          height: ui.item.innerHeight() - 15 + 1, //account for margin and border    
          padding: ui.item.css("padding"), //use original padding
          marginTop: 0 //dispose of the jQuery margin
        });       

    }
  }
});

Here's a working fiddle example

I made sure to test this in all responsive modes

enter image description here

like image 163
OpherV Avatar answered Nov 07 '22 20:11

OpherV


OpherV solution works. Here's however a simplified version that still works and tries to keep separation of concerns by leaving CSS matters on the CSS code. I've tried to keep padding/margin interactions on the js code itself minimum.

The idea is the same, I get the width and height directly from the .panel, and I copy as is all the classes on the col- div. But margins and paddings are set via CSS to match Bootstrap's Default.

You can find it on the snippet below, or here on the jsfiddle. https://jsfiddle.net/zdfb3e0p/16/

$('.row').sortable({
     connectWith: ".panel",
     handle: ".panel-heading",
     placeholder: "panel-placeholder",
     start: function(e, ui){
         ui.placeholder.width(ui.item.find('.panel').width());
         ui.placeholder.height(ui.item.find('.panel').height());
         ui.placeholder.addClass(ui.item.attr("class"));
     }
});

$('.panel').on('mousedown', function(){
  $(this).css( 'cursor', 'move' );
}).on('mouseup', function(){
  $(this).css( 'cursor', 'auto' );
});;
.panel-placeholder {
  border: 1px dotted black;
  border-radius: 4px;
  margin: 0 15px 20px 15px;
  padding: 0;
  height: 50px;
}
<script src="https://code.jquery.com/jquery-3.0.0.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet"/>
<div class="container-fluid">
	<div class="row">
		<div class="col-md-3">
			<div class="panel panel-primary">
				<div class="panel-heading">
					<h3 class="panel-title">Panel title</h3>
				</div>
				<div class="panel-body">
					Panel content
				</div>
			</div>
		</div>
		<div class="col-md-4">
			<div class="panel panel-primary">
				<div class="panel-heading">
					<h3 class="panel-title">Panel title</h3>
				</div>
				<div class="panel-body">
					Panel content
				</div>
			</div>
		</div>
		<div class="col-md-8">
			<div class="panel panel-primary">
				<div class="panel-heading">
					<h3 class="panel-title">Panel title</h3>
				</div>
				<div class="panel-body">
					Panel content
				</div>
			</div>
		</div>
	</div>
</div>
like image 45
Juan Ferreras Avatar answered Nov 07 '22 19:11

Juan Ferreras


Bootstrap's Grid system has a default 30px padding (15px per side). Since you are tying the sort to .row you need to account for that. Changing your margin value on .panel-placeholder to 15px will cause it to fall in line with Bootstrap's Grid Framework.

$('.row').sortable({
	connectWith: ".panel",
	handle: ".panel-heading",
	placeholder: "panel-placeholder"
});

$('.panel').on('mousedown', function(){
	$(this).css( 'cursor', 'move' );
}).on('mouseup', function(){
	$(this).css( 'cursor', 'auto' );
});;
.panel-placeholder {
	border: 1px dotted black;
	margin: 15px;
	height: 50px;
}
<script src="https://code.jquery.com/jquery-3.0.0.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet"/>
<div class="container-fluid">
	<div class="row">
		<div class="col-md-3">
			<div class="panel panel-primary">
				<div class="panel-heading">
					<h3 class="panel-title">Panel title</h3>
				</div>
				<div class="panel-body">
					Panel content
				</div>
			</div>
		</div>
		<div class="col-md-4">
			<div class="panel panel-primary">
				<div class="panel-heading">
					<h3 class="panel-title">Panel title</h3>
				</div>
				<div class="panel-body">
					Panel content
				</div>
			</div>
		</div>
		<div class="col-md-3">
			<div class="panel panel-primary">
				<div class="panel-heading">
					<h3 class="panel-title">Panel title</h3>
				</div>
				<div class="panel-body">
					Panel content
				</div>
			</div>
		</div>
	</div>
</div>

https://jsfiddle.net/Lhmujrzz/

like image 23
Robert Avatar answered Nov 07 '22 20:11

Robert