<!DOCTYPE html>
<html>
<head>
<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="jquery@*" data-semver="2.0.3" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<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.0-rc3-nonmin" data-semver="1.2.0-rc3-nonmin" src="http://code.angularjs.org/1.2.0-rc.3/angular.js"></script>
<script src="sortable.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="myapp" ng-controller="ctrl">
<h1>Hello Plunker!</h1>
<ul psi-sortable="" ng-model="list">
<li ng-repeat="item in list track by $index"> {{item}} </li>
</ul>
<hr>
<div ng-repeat="item in list track by $index" > {{item}} </dov>
</body>
</html>
// Code goes here
angular.module('myapp', ['psi.sortable']);
function ctrl($scope) {
setTimeout(function(){
$scope.$apply(function(){
$scope.list = ['first', 'second', 'third', 'last'];
});
}, 500);
}
li {
border: 1px solid;
cursor: move;
background: #ccc;
padding: 5px;
margin-bottom: 5px;
}
angular.module('psi.sortable', [])
.value('psiSortableConfig', {
placeholder: "placeholder",
opacity: 0.8,
axis: "y",
helper: 'clone',
forcePlaceholderSize: true
})
.directive("psiSortable", ['psiSortableConfig', '$log', function(psiSortableConfig, $log) {
return {
require: '?ngModel',
link: function(scope, element, attrs, ngModel) {
if(!ngModel) {
$log.error('psiSortable needs a ng-model attribute!', element);
return;
}
var opts = {};
angular.extend(opts, psiSortableConfig);
opts.update = update;
// listen for changes on psiSortable attribute
scope.$watch(attrs.psiSortable, function(newVal) {
angular.forEach(newVal, function(value, key) {
element.sortable('option', key, value);
});
}, true);
// store the sortable index
scope.$watch(attrs.ngModel+'.length', function() {
element.children().each(function(i, elem) {
jQuery(elem).attr('sortable-index', i);
});
});
// jQuery sortable update callback
function update(event, ui) {
// get model
var model = ngModel.$modelValue;
// remember its length
var modelLength = model.length;
// rember html nodes
var items = [];
// loop through items in new order
element.children().each(function(index) {
var item = jQuery(this);
// get old item index
var oldIndex = parseInt(item.attr("sortable-index"), 10);
// add item to the end of model
model.push(model[oldIndex]);
if(item.attr("sortable-index")) {
// items in original order to restore dom
items[oldIndex] = item;
// and remove item from dom
item.detach();
}
});
model.splice(0, modelLength);
// restore original dom order, so angular does not get confused
element.append.apply(element, items);
// notify angular of the change
scope.$digest();
}
element.sortable(opts);
}
};
}]);