在AngularJS中拖放可排序的ng:重复?

Posted

技术标签:

【中文标题】在AngularJS中拖放可排序的ng:重复?【英文标题】:Drag and drop sortable ng:repeats in AngularJS? 【发布时间】:2011-11-13 09:01:07 【问题描述】:

在 AngularJS 中的 ng-repeat 元素上使用 jQuery.sortable 是否容易?


如果重新排序项目会自动将该排序传播回源数组,那就太棒了。恐怕这两个系统会打架。有没有更好的方法来做到这一点?

【问题讨论】:

您是否可以更新 Angular js 当前版本的 js fiddle 代码,即 Angular js 1.0.1。我尝试通过根据我的要求将 angular js 的版本更改为 1.0.1 来在 jsfiddle 上运行示例,但随后代码中断并且不起作用。请帮忙。谢谢! 我同意这一点。还在寻找 1.0.1 的工作示例 :-) 找到了这个,在 1.0.1 中工作 - jsfiddle.net/007design/KHqbM 我创建了一个教程,介绍如何结合 JQuery UI 执行此操作。使用单个指令很容易做到。解释和例子可以在这里找到:smartjava.org/content/drag-and-drop-angularjs-using-jquery-ui 【参考方案1】:

Angular UI 有一个可排序的指令,Click Here for Demo

代码位于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')) 

【讨论】:

请注意,您应该添加ng-modelui:sortable&lt;ul ui:sortable ng:model="list"&gt; 控制台有错误吗?在我的 chrome/windows 7 中工作,您可以尝试更新库(jquery/jqueryUI/angular/angularUI),看看它是否解决了您的问题... jsfiddle 示例似乎不能可靠地工作。没有错误,但订单间歇性地变得不同步。在 Firefox 和 chrome 中尝试过 知道如何在没有 jQuery 的情况下实现这一目标吗? @Kugel 你有没有尝试过 angular-ui sortable 的最后一个版本?以角度发展的速度,演示很快就会过时:github.com/angular-ui/ui-sortable【参考方案2】:

我尝试做同样的事情并想出了以下解决方案:

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 todo 教程创建了一个 JsFiddle 来展示它是如何工作的:http://jsfiddle.net/M8YnR/180/

【讨论】:

【参考方案3】:

这就是我使用 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,但我相信你的话,这是可行的。 此解决方案需要注意的一点是,它很可能无法像 v1.x 那样工作。调整这个应该不难,但我还没有开始更新我的所有代码。 @respectTheCode 您是否重构了代码以使用最新的 AngularJS 版本(v1.0.1)?我一辈子都找不到可靠的 1.0.1 工作版本...... @Greg 我们现在正在使用 Angular-UI 的 UI-Sortable,效果很好。 github.com/angular-ui/ui-sortable【参考方案4】:

这是我在没有 jquery.ui 的情况下实现可排序的 Angular.js 指令:

https://github.com/schartier/angular-sortable

【讨论】:

【参考方案5】:

您可以选择轻量级且不使用 jquery 的 ng-sortable 指令。这是链接ng-sortable drag and drop elements

Demo for ng-sortable

【讨论】:

以上是关于在AngularJS中拖放可排序的ng:重复?的主要内容,如果未能解决你的问题,请参考以下文章

在 AngularJS 应用程序中拖放的自定义指令

拖放可排序列表的问题

通过拖放可重新排序的 ListView

使用 ReactJs 和 react-dnd 拖放可排序列表的问题

嵌套可排序 AngularJS

嵌套 ng-repeat 拖放,AngularJS