First, we need a way to tie the elements to the objects in our model. We can do this by giving our elements in the repeater an ID and grabbing that ID when the sort stops.
<ul sortable>
<li id="elem-{{obj.id}}" ng-repeat="obj in objects">
{ obj.message }}
</li>
</ul>
Now in our directive we need to use the sortable's toArray method (documentation here) to get a list of all element IDs and their positions and we need to pass that into our syncOrder function.
app.directive('sortable', function ($timeout) {
return function (scope, element, attributes) {
element.sortable({
stop: function(event, ui){
scope.syncOrder(element.sortable('toArray'));
}
});
};
});
Now we can modify our syncOrder function to iterate over all objects in our model, then iterate over all elements in the array passed in by sortable, compare the IDs, and update the model to reflect the new positions.
$scope.syncOrder = function (elemPositions) {
// loop over our model objects
$scope.objects.forEach(function (obj) {
// loop over all the element positions
elemPositions.forEach(function (elemId, index) {
// shave off the string part of the ID on the element.
var id = parseInt(elemId.replace(/elem-/, ''));
// Items in the elemPositions array are in the order that they
// are on the page. If the element ID matches the ID we gave to
// our object, update the sort order to match the current index.
if (id === obj.id) {
obj.sortOrder = index;
}
});
});
};
Once we have that setup there's one final thing we need to do. The stop event from the jquery sortable widget is executed outside of the angular execution block. In other words, angular has no way to know exactly if or when the sortable is going to update its objects array on our $scope. Because of this, your view will appear to not update when you sort; though if you iterate over your array you would see the array did indeed update.
We need to force angular to be aware that changes are about to happen to objects in scope. To do this we'll call scope.$apply in our directive.
return function (scope, element, attributes) {
element.sortable({
stop: function(event, ui){
// Without this, angular magic won't happen when the objects array is updated.
scope.$apply(function () {
scope.syncOrder(element.sortable('toArray'));
});
}
});
};