<!DOCTYPE html>
<html ng-app="ui-sortable-multiselect" ng-controller="MultiSelectDemo">
<head>
<script data-require="jquery@*" data-semver="2.0.3" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<link data-require="jqueryui@*" data-semver="1.10.0" rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.10.0/css/smoothness/jquery-ui-1.10.0.custom.min.css" />
<script data-require="jqueryui@*" data-semver="1.10.0" src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.10.0/jquery-ui.js"></script>
<script data-require="angular.js@1.2.17" data-semver="1.2.17" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js"></script>
<script data-require="underscore.js@*" data-semver="1.6.0" src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js"></script>
<script src="https://rawgit.com/angular-ui/ui-sortable/d9911be26fb0227659c53fe9f4a4147bb2874dc0/src/sortable.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<h2>Multi-select sortable with AngularJS</h2>
<p>
<code>Click</code> to select individual items</p>
<p>
<code>Ctrl + Click</code> to select multiple items</p>
<p>
<code>Shift + Click</code> to select multiple items</p>
<div class="list-manager">
<div class="loading-overlay" ng-show="actingOnThings">
<span class="fa fa-spin fa-spinner"></span> Doing a thing...
</div>
<div>
<input type="text" />
<button>Add</button>
</div>
<div class="list">
<h2>Trash, And Similar Things</h2>
<ul multi-select="itemsInTrash" multi-select-function="selectItem" ui-sortable="sortableOptions" class="list list-container" ng-model="itemsInTrash"></ul>
<!--
<button class="selectAll" data-bind="click: selectAllItemsIn.bind(this, userList1)">Select All</button>
<button class"moveSelected" data-bind="click: moveAllFunction(userList1, userList2)">Move Selected</button>
-->
</div>
<div class="list">
<h2>Actual Things, Like For Real</h2>
<ul multi-select="itemsThatAreReal" multi-select-function="selectItem" ui-sortable="sortableOptions" class="list list-container" ng-model="itemsThatAreReal"></ul>
<!--
<button class"moveSelected" data-bind="click: moveAllFunction(userList2, userList1)">Move Selected</button>
<button class="selectAll" data-bind="click: selectAllItemsIn.bind(this, userList2)">Select All</button>
-->
</div>
</div>
</body>
</html>
angular.module('ui-sortable-multiselect', ['ui.sortable'])
.directive('multiSelect', function() {
return {
restrict: 'AE',
scope: {
itemList: '=multiSelect',
selectItem: '=multiSelectFunction'
},
templateUrl: 'list-item-template.html'
}
})
.controller('MultiSelectDemo', ['$scope', function($scope) {
$scope.actingOnThings = false;
$scope.itemsInTrash = [
{ id: 1, name: "Test 1", selected: false },
{ id: 2, name: "Test 2", selected: false },
{ id: 3, name: "Test 3", selected: false }
];
$scope.itemsThatAreReal = [
{ id: 4, name: "Test 4", selected: false },
{ id: 5, name: "Test 5", selected: false },
{ id: 6, name: "Test 6", selected: false }
];
/*for(var i=4; i<7; i++) {
$scope.itemsThatAreReal.push({
id: i, name: "Test "+i, selected: false
});
console.log($scope.itemsThatAreReal);
}*/
$scope.lastArray = null;
var moveTheseTo = function(items, from, to, atPosition) {
//console.log(items, from, to, atPosition)
if(!items.length) return;
if(self.actingOnThings) return;
self.actingOnThings = true;
//copy things from one list to the next
var copyFunction = function() {
var newArgs = [atPosition, 0].concat(items);
angular.forEach(items, function(item) {
from.splice(from.indexOf(item), 1);
item.selected = false;
});
console.log(to);
to.splice.apply(to, newArgs);
console.log(to);
self.actingOnThings = false;
console.log("no longer acting on things",items.length);
$scope.$apply();
}
if(items.length > 300) {
setTimeout(copyFunction, 100);
} else {
copyFunction();
}
};
$scope.sortableOptions = {
revert: 100,
tolerance: "pointer",
distance: 15,
connectWith: ".list-container",
update: function(event, ui) {
//prevent an error
if(typeof ui.item.scope() === 'undefined') return;
var myList = ui.item.scope().itemList;
var newList = $scope.$eval(ui.item.sortable.droptarget.attr('ng-model'));
var newIndex = ui.item.sortable.dropindex;
//get the currently active items
var items = myList.filter(function(item) {
return item.selected;
});
moveTheseTo(items, myList, newList, newIndex);
//cancel drop, since I handle the movement myself
ui.item.sortable.cancel();
},
helper: function(event, $item) {
//select the unselected (if you're dragging something not previously selected)
if(!$item.hasClass('selected')) {
$item.parent().children().removeClass('selected');
$item.scope().item.selected = true;
$item.addClass('selected');
angular.forEach($scope.lastArray, function(item) {
item.selected = item.id == $item.data('id');
});
}
// show "you have x items selected" if x > 1
var $selected = $item.parent().find('.selected');
var $helper;
if ($selected.size() > 1) {
$helper = $('<li class="item selected">You have ' + $selected.size() + ' items selected.</li>');
$selected.removeClass('selected');
} else {
$helper = $selected;
}
return $helper;
}
};
$scope.selectItem = function(event, array, $data) {
$scope.lastArray = array;
//default selection
if (!event.ctrlKey && !event.metaKey && !event.shiftKey) {
$data.selected = true
angular.forEach(array, function(item) {
if (item !== $data) {
item.selected = false
}
});
//shift-key selection
} else if (event.shiftKey && !event.ctrlKey && $scope._lastSelectedIndex > -1) {
var myIndex = array.indexOf($data);
if (myIndex > $scope._lastSelectedIndex) {
for (var i = $scope._lastSelectedIndex; i <= myIndex; i++) {
array[i].selected = true;
}
} else if (myIndex < $scope._lastSelectedIndex) {
for (var i = myIndex; i <= $scope._lastSelectedIndex; i++) {
array[i].selected = true;
}
}
//ctrl key selection
} else if (event.ctrlKey && !event.shiftKey) {
$data.selected = !$data.selected;
}
//keep track of the index for shift-key stuff
$scope._lastSelectedIndex = array.indexOf($data);
};
}]);
.item {
cursor: pointer;
padding-left: 10px;
}
.item.selected {
background-color:#1e91fc;
color: #fff;
cursor: move;
}
div.list {
display: inline-block;
vertical-align: top;
width: 300px;
max-width: 350px;
}
div.list ul.list {
max-height: 400px;
height: 400px;
overflow-y: scroll;
}
.list {
padding: 0;
background-color: #fafafa;
border: 1px solid #CCC;
list-style-type: none;
margin: 0;
}
.list-manager {
position: relative;
display: table-cell;
}
.loading-overlay {
position: absolute;
line-height: 400px;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color:#fafafa;
filter:alpha(opacity=90);
opacity:0.9;
-moz-opacity:0.9;
z-index:100;
text-align:center;
vertical-align:middle;
}
<li class="item"
ng-repeat="item in itemList track by item.id"
ng-click="selectItem($event, itemList, item)"
ng-class="{selected: item.selected}"
data-id="{{item.id}}"
>{{ item.name }}</li>