angularjs sortable - 更新排序顺序属性

Jas*_*gar 1 jquery jquery-ui jquery-ui-sortable angularjs

我正在创建一个angularjs应用程序,它也使用jquery ui sortable.我正在寻找一种干净的方法来根据它们在页面上的位置更新我的模型上的"SortOrder"属性,每次执行排序时.

这是我到目前为止所拥有的:

<div class="object-container" sortable>
    <div ng-repeat="object in objects">
        <div class="obj-title">{{object.Title}}</div>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

这是我的可排序指令:

myApp.directive('sortable', function(){
    return {
        restrict : 'A',
        link : function(scope, element, attributes){
            element.sortable({
                helper : 'clone',
                stop : function(event, ui){
                    scope.syncOrder();
                }
            });
        }
    };
});
Run Code Online (Sandbox Code Playgroud)

而我的"syncOrder"功能:

$scope.syncOrder = function(){
    // some speculation here:
    for(var i in $scope.objects){
        $scope.objects[i].SortOrder = ???;
    }
};
Run Code Online (Sandbox Code Playgroud)

SortOrder属性存在并在页面加载时设置,但显然它们需要在排序时更新,因此我可以将更新的集合传递回服务器并保存.有任何想法吗?

谢谢!

Che*_*hev 6

首先,我们需要一种方法将元素绑定到模型中的对象.我们可以通过在转发器中为我们的元素提供ID并在排序停止时获取该ID来实现此目的.

<ul sortable>
    <li id="elem-{{obj.id}}" ng-repeat="obj in objects">
        { obj.message }}
    </li>
</ul>
Run Code Online (Sandbox Code Playgroud)

现在在我们的指令中,我们需要使用sortable的toArray方法(这里的文档)来获取所有元素ID及其位置的列表,我们需要将它传递给我们的syncOrder函数.

app.directive('sortable', function ($timeout) {
  return function (scope, element, attributes) {
    element.sortable({
        stop: function(event, ui){
            scope.syncOrder(element.sortable('toArray'));
        }
    });
  };
});
Run Code Online (Sandbox Code Playgroud)

现在我们可以修改我们的syncOrder函数来遍历模型中的所有对象,然后迭代通过sortable传入的数组中的所有元素,比较ID,并更新模型以反映新的位置.

$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;
            }
        });
    });
};
Run Code Online (Sandbox Code Playgroud)

一旦我们完成了这个设置,我们需要做的最后一件事就是.stop来自jquery可排序小部件的事件在角度执行块之外执行.换句话说,angular无法准确知道sortable 是否何时将更新其objects数组$scope.因此,您的视图在排序时似乎不会更新; 虽然如果你遍历你的数组,你会看到数组确实更新.

我们需要强制角度来意识到变化即将发生在范围内的对象上.要做到这一点,我们将scope.$apply在我们的指令中调用.

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'));
            });
        }
    });
};
Run Code Online (Sandbox Code Playgroud)

工作演示