Я попытался сделать то же самое и придумал следующее решение:
angular.directive("my:sortable", function(expression, compiledElement){
return function(linkElement){
var scope = this;
linkElement.sortable(
{
placeholder: "ui-state-highlight",
opacity: 0.8,
update: function(event, ui) {
var model = scope.$tryEval(expression);
var newModel = [];
var items = [];
linkElement.children().each(function() {
var item = $(this);
// get old item index
var oldIndex = item.attr("ng:repeat-index");
if(oldIndex) {
// new model in new order
newModel.push(model[oldIndex]);
// items in original order
items[oldIndex] = item;
// and remove
item.detach();
}
});
// restore original dom order, so angular does not get confused
linkElement.append.apply(linkElement,items);
// clear old list
model.length = 0;
// add elements in new order
model.push.apply(model, newModel);
// presto
scope.$eval();
// Notify event handler
var onSortExpression = linkElement.attr("my:onsort");
if(onSortExpression) {
scope.$tryEval(onSortExpression, linkElement);
}
}
});
};
});
Используется так:
<ol id="todoList" my:sortable="todos" my:onsort="onSort()">
Кажется, это работает довольно хорошо. Хитрость заключается в том, чтобы отменить манипулирование DOM, выполняемое сортируемым, перед обновлением модели, в противном случае agular будет десинхронизирован из DOM.
Уведомление об изменениях работает через выражение my: onsort, которое может вызывать методы контроллера.
Я создал JsFiddle на основе учебника по угловым задачам, чтобы показать, как он работает: http://jsfiddle.net/M8YnR/180/