This code was actually written for the purpose of creating printed labels for products. The labels below would be the individual products and allow the user to sort them into containers together for the puropse of organizing them in the same way they are organized in their respective shipping boxes. I added an extra button for adding more labels to allow for you to play around with as many as you'd like.
<div class="row containerHeader">
<div class="col-sm-12">
<div class="row">
<div class="col-sm-6">
<h3>
Create Containers
</h3>
<p>
Drag the inputs to the outer containers below.
</p>
</div>
<div class="col-sm-6">
<div class="btn-toolbar pull-right" role="toolbar">
<div class="btn-group">
<a id="addLabel" class="btn btn-md btn-primary">
+ Label
</a>
</div>
<div class="btn-group">
<a id="addLabelContainer" class="btn btn-md btn-primary">
+ Label Container
</a>
</div>
</div>
</div>
</div>
<div class="row">
<hr>
</div>
<div style="display:none;">
<div class="col-sm-2 cloneElm">
<li class="list-group-item active" labelNumber="label_{{n}}">
Label {{n}}
<input type="hidden" name="label_{{n}}" value="label_{{n}}_value">
</li>
</div>
</div>
<div class="row labelTopContainer">
<div class="col-sm-12 text-center">
<ul class="list-group">
<div class="col-sm-2">
<li class="list-group-item active" labelNumber="label_1">
Label 1
<input type="hidden" name="label_1" value="label_1_value">
</li>
</div>
<div class="col-sm-2">
<li class="list-group-item active" labelNumber="label_2">
Label 2
<input type="hidden" name="label_2" value="label_2_value">
</li>
</div>
<div class="col-sm-2">
<li class="list-group-item active" labelNumber="label_3">
Label 3
<input type="hidden" name="label_3" value="label_3_value">
</li>
</div>
</ul>
</div>
</div>
<div style="display:none;">
<div class="labelContainer">
<div class="col-sm-4">
<a href="javascript:void(0);" class="removeLabelContainer" onClick="removeLabelContainer(this);">
<span class="glyphicon glyphicon-remove pull-right" aria-hidden="true"></span>
</a>
<h4>
Label Container {{n}}
</h4>
<ul class="list-group text-center">
</ul>
<input type="hidden" name="labelContainer_{{n}}" value="">
</div>
</div>
</div>
<div class="row">
<hr>
</div>
<div class="row outerContainer">
<div class="innerContainer">
<div class="labelContainer">
<div class="col-sm-4">
<a href="javascript:void(0);" class="removeLabelContainer" onClick="removeLabelContainer(this);">
<span class="glyphicon glyphicon-remove pull-right" aria-hidden="true"></span>
</a>
<h4>
Label Container 1
</h4>
<ul class="list-group text-center">
</ul>
<input type="hidden" name="labelContainer_1" value="">
</div>
</div>
</div>
<div class="clearfix hidden-xs"></div>
<div class="col-sm-12">
<div class="btn-toolbar" role="toolbar">
<div class="btn-group">
<a class="btn btn-md btn-success" onClick="alert('This is just for testing purposes.');">
Save
</a>
</div>
</div>
</div>
</div>
</div>
</div>
.containerHeader {
margin-top: 20px;
}
.containerHeader h3 {
margin-top: 0px;
}
.labelTopContainer .list-group-item {
margin-bottom: 10px;
}
.outerContainer .labelContainer:nth-child(3n-5) .col-sm-4 {
clear: left;
}
.labelContainer h4 {
margin-top: 0px;
}
.labelContainer .glyphicon {
color: red;
}
.labelContainer .list-group {
min-height: 50px;
border: 1px solid #dddddd;
padding: 10px;
}
.labelContainer .list-group-item, .labelContainer .list-group-item:hover, .labelContainer .list-group-item:focus {
border: 1px solid #ffffff;
}
$(function(){
$('.outerContainer .list-group').sortable({
revert: true,
connectWith: ".outerContainer .list-group",
receive: function(event, ui) {
$(this).closest('.labelContainer').find('.removeLabelContainer').remove();
},
update: function(event, ui) {
$('.labelContainer .list-group').each(function(index, value){
if (index > 0) {
var getLiLength = $(this).find('li').length;
var checkRemoveButton = $(this).closest('.labelContainer').find('.removeLabelContainer').length;
if (!getLiLength && !checkRemoveButton) {
$(this).closest('.col-sm-4').prepend('');
}
}
});
}
});
$('.labelTopContainer .list-group-item').draggable({
connectToSortable: ".outerContainer .list-group",
revert: "invalid",
stop: function(event, ui) {
if ($(this).hasClass('ui-sortable-helper')) {
$('.labelTopContainer .col-sm-2').each(function(){
var checkContainer = $(this).find('.list-group-item').length;
if (!checkContainer) {
$(this).remove();
}
});
}
}
});
$('#addLabelContainer').on('click', function(){
var elmCount = $('.labelContainer').length;
var $cloneElm = $('.labelContainer:first').clone();
$cloneElm.find('h4').text('Label Container ' + elmCount);
$cloneElm.find('input[name^="labelContainer"]').attr('name', 'labelContainer_' + elmCount);
$cloneElm.find('.list-group').sortable({
revert: true,
connectWith: ".outerContainer .list-group",
receive: function(event, ui) {
$(this).closest('.labelContainer').find('.removeLabelContainer').remove();
},
update: function(event, ui) {
$('.labelContainer .list-group').each(function(index, value){
if (index > 0) {
var getLiLength = $(this).find('li').length;
var checkRemoveButton = $(this).closest('.labelContainer').find('.removeLabelContainer').length;
if (!getLiLength && !checkRemoveButton) {
$(this).closest('.col-sm-4').prepend('');
}
}
});
}
});
$('.outerContainer .innerContainer').append($cloneElm);
});
addLabel();
});
function removeLabelContainer(e) {
$(e).closest('.labelContainer').remove();
updateContainerNumbers();
}
function updateContainerNumbers() {
$('.labelContainer').each(function(index, value){
if (index > 0) {
$(this).find('h4').text('Label Container ' + (index));
$(this).find('input[name^="labelContainer_"]').attr('name', 'labelContainer_' + (index));
}
});
}
function addLabel() {
$('#addLabel').on('click', function(){
var labelCount = parseInt($('.list-group-item').length);
var $cloneElm = $('.cloneElm').clone();
$cloneElm.removeClass('cloneElm');
$cloneElm.find('.list-group-item').text('Label ' + labelCount);
$cloneElm.find('.list-group-item').attr('labelNumber','label_' + labelCount);
$cloneElm.find('.list-group-item input').val('label_' + labelCount + '_value');
$cloneElm.find('.list-group-item').draggable({
connectToSortable: ".outerContainer .list-group",
revert: "invalid",
stop: function(event, ui) {
if ($(this).hasClass('ui-sortable-helper')) {
$('.labelTopContainer .col-sm-2').each(function(){
var checkContainer = $(this).find('.list-group-item').length;
if (!checkContainer) {
$(this).remove();
}
});
}
}
});
$('.labelTopContainer .list-group').append($cloneElm);
});
}