在AngularJS中,如何拖放排序ng:repeats?

63

在AngularJS中,对于使用了ng-repeat的元素使用jQuery.sortable是否容易?


如果重新排序项目可以自动传播到源数组中,那将会非常棒。但我担心这两个系统会产生冲突。有更好的方法吗?


请问您能否更新 AngularJS 当前版本(即 AngularJS 1.0.1)的 JSFiddle 代码呢?我尝试根据我的需求将 AngularJS 版本更改为 1.0.1 并在 JSFiddle 上运行示例,但代码会出错并无法正常工作。恳请您的帮助。谢谢! - Basmah
我同意这个。同时也在寻找1.0.1的工作示例 :-) - Marco Johannesen
发现这个,在1.0.1中有效 - http://jsfiddle.net/007design/KHqbM/ - Marco Johannesen
2
我已经创建了一个关于如何与JQuery UI结合实现此操作的教程。只需要一个指令就可以轻松完成。可以在这里找到说明和示例:http://www.smartjava.org/content/drag-and-drop-angularjs-using-jquery-ui - Jos Dirksen
5个回答

79

Angular UI提供了一个可排序的指令,点击这里查看演示

代码位于ui-sortable,用法:

<ul ui-sortable ng-model="items" ui-sortable-update="sorted">
  <li ng-repeat="item in items track by $index" id="{{$index}}">{{ item }}</li>
</ul>
$scope.sorted = (event, ui) => { console.log(ui.item[0].getAttribute('id')) }

2
请注意,在 ui:sortable 中应添加 ng-model<ul ui:sortable ng:model="list"> - Vladimir Starkov
1
控制台有任何错误吗?在我的Chrome / Windows 7上可以正常工作,您可以尝试更新库(jquery / jqueryUI / angular / angularUI)并查看是否解决了您的问题... - Guillaume86
17
jsfiddle的例子似乎不太可靠。没有错误,但是顺序偶尔会失去同步。已尝试在Firefox和Chrome中操作。 - Chris Foster
13
没有使用jQuery,有什么方法可以实现这个? - Pavel Nikolov
3
@Kugel,你有尝试过angular-ui sortable的最新版本吗?随着Angular的不断发展,演示很快就会过时:https://github.com/angular-ui/ui-sortable - Guillaume86
显示剩余9条评论

12

我尝试了同样的方法,并想出了以下解决方案:

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()">

看起来工作得相当不错。诀窍是在更新模型之前撤消由sortable所做的DOM操作,否则Angular会与DOM不同步。

通过my:onsort表达式通知变化,它可以调用控制器方法。

我创建了一个基于Angular待办事项教程的JsFiddle演示它的工作原理:http://jsfiddle.net/M8YnR/180/


10

这是我在使用 Angular v0.10.6 时的方法。这是 jsfiddle

angular.directive("my:sortable", function(expression, compiledElement){
    // add my:sortable-index to children so we know the index in the model
    compiledElement.children().attr("my:sortable-index","{{$index}}");

    return function(linkElement){
        var scope = this;            

        linkElement.sortable({
            placeholder: "placeholder",
            opacity: 0.8,
            axis: "y",
            update: function(event, ui) {
                // get model
                var model = scope.$apply(expression);
                // remember its length
                var modelLength = model.length;
                // rember html nodes
                var items = [];

                // loop through items in new order
                linkElement.children().each(function(index) {
                    var item = $(this);

                    // get old item index
                    var oldIndex = parseInt(item.attr("my:sortable-index"), 10);

                    // add item to the end of model
                    model.push(model[oldIndex]);

                    if(item.attr("my: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
                linkElement.append.apply(linkElement,items);

                // notify angular of the change
                scope.$digest();
            }
        });
    };
});

我最终只使用了SlickGrid,但我会相信你的话,这也可以。 - Nick Retallack
需要注意的是,这个解决方案很可能不能直接在v1.x上使用。调整一下应该不难,但我还没有更新所有的代码。 - respectTheCode
@respectTheCode 你重构了代码以适应最新的AngularJS版本(v1.0.1)吗?我怎么也找不到一个可靠的适用于1.0.1的工作版本... - Greg
1
@Greg,我们现在正在使用Angular-UI的UI-Sortable,它非常好用。https://github.com/angular-ui/ui-sortable - respectTheCode

6

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接