在多个选择中上下移动元素不起作用

Ale*_*Man 4 html javascript select dropdownbox angularjs

我创建了一个带有多个选择的angularjs应用程序,我有上下按钮,当我点击上下按钮时,应该在多个选择内完成相应的项目移动,我有一个已经完成的示例内容正常的javascript正确地执行类似的事情,就像在这个小提琴中所示,但当我试图在AngularJS中实现相同的东西时,它无法正常工作

任何人都可以告诉我一些解决方案

我的代码如下所示

的jsfiddle

HTML

<div ng-app='myApp' ng-controller="ArrayController">
    <select id="select" size="9" ng-model="persons" ng-options="item as item.name for item in peoples | orderBy:'name'" multiple></select>
    <br/>
    <button ng-click="moveUp()">Up</button>
    <br/>
    <button ng-click="moveDown()">Down</button>
    <br/>
</div>
Run Code Online (Sandbox Code Playgroud)

脚本

var app = angular.module('myApp', []);
app.controller('ArrayController', function ($scope) {
    $scope.peoples = [{
        name: 'Jacob'
    }, {
        name: 'Sunny'
    }, {
        name: 'Lenu'
    }, {
        name: 'Mathew'
    }, {
        name: 'Ferix'
    }, {
        name: 'Kitex'
    }];

    $scope.moveUp = function () {
        var select = document.getElementById("select");
        var i1=0, i2=1;
        while (i2 < select.options.length) {
            swapIf(select,i1++,i2++);
        }
    };

    $scope.moveDown = function () {
        var select = document.getElementById("select");
        var i1=select.options.length-1, i2=i1-1;
        while (i1 > 0) {
            swapIf(select,i1--,i2--);
        }
    };

    var swapVar = '';
    function swapIf(sel,i1,i2) {
        if ( ! select[i1].selected && select[i2].selected) {
            swapVar = select[i2].text;
            select[i2].text = select[i1].text;
            select[i1].text = swapVar;
            swapVar = select[i2].value;
            select[i2].value = select[i1].value;
            select[i1].value = swapVar;
            select[i1].selected = true;
            select[i2].selected = false;
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

tpi*_*pie 7

persons将返回列表中所选项目的数组.一种解决方案是创建一个for循环来获取数组indexOf中每个项目的内容persons.数组splice中的项目peoples,递增/递减索引,然后splice返回到peoples数组.

这是一个moveUp()可以向上移动多个选定项目的新功能:

   $scope.moveUp = function () {
        for(var i = 0; i < $scope.persons.length; i++) {
            var idx = $scope.peoples.indexOf($scope.persons[i])
            console.log(idx);
            if (idx > 0) {
                var itemToMove = $scope.peoples.splice(idx, 1)
                console.log(itemToMove[0])
                $scope.peoples.splice(idx-1, 0, itemToMove[0]);

            }
        }
    };
Run Code Online (Sandbox Code Playgroud)

这是更新的moveDown()功能:

   $scope.moveDown = function () {
        for(var i = 0; i < $scope.persons.length; i++) {
            var idx = $scope.peoples.indexOf($scope.persons[i])
            console.log(idx);
            if (idx < $scope.peoples.length) {
                var itemToMove = $scope.peoples.splice(idx, 1)
                console.log(itemToMove[0])
                $scope.peoples.splice(idx+2, 0, itemToMove[0]);

            }
        }
    };    
Run Code Online (Sandbox Code Playgroud)

这是工作演示(工作不正常,仅供参考 - 见下文)

此解决方案还保持视图和控制器之间的分离.控制器具有操纵数据的作用,视图显示该数据.这样我们就可以避免任何不合理的纠缠.控制器内的DOM操作非常难以测试.

经过一些修改后编辑: 所以我以前的解决方案在某些情况下工作,但会用不同的选择组合执行奇怪的操作.经过一番挖掘,我发现有必要通过以下方式添加轨道:

<select id="select" size="9" ng-model="persons" ng-options="item as item.name for item in peoples track by item.name" multiple>

似乎选择会返回persons具有任意选择顺序的对象,这会搞砸事情,特别是在您点击几次之后,它似乎对事情的位置感到困惑.

另外,我必须在向下移动项目时克隆和反转人员阵列,因为在添加track by item.name项目时会按顺序返回项目,但如果您尝试迭代数组,将每个项目向下移动,则可能会影响其他项目的位置.数组(进一步产生不可预测的行为).所以我们需要从底部开始,在向下移动多个项目时继续前进.

这是一个解决方案,在我做出多个任意选择时,我似乎已经消除了任何不可预测的行为:

工作演示

编辑: 我发现的一个错误是,当您将多个选定的项目一直向上或向下移动时会发生奇怪的事情,然后再尝试将其向该方向移动一次.没有重新选择的任何进一步运动都会产生不可预测的结果.

编辑: 上一次编辑中提到的不可预测的行为是因为函数看到了,虽然第一项是在它的最终位置,第二,第三,第四等项目​​不在最终位置,因此它试图移动它们导致疯狂地重新排序已经将所有项目推到顶部或底部的项目.为了解决这个问题,我设置了一个var来跟踪先前移动的项目的位置.如果发现当前项目处于相邻位置,则只需将其保留在那里并继续前进.

最终函数看起来像这样:

$scope.moveUp = function () {
        var prevIdx = -1;
        var person = $scope.persons.concat();
        console.log($scope.persons);
        for(var i = 0; i < $scope.persons.length; i++) {
            var idx = $scope.peoples.indexOf($scope.persons[i])
            console.log(idx);
            if (idx-1 === prevIdx) {
                prevIdx = idx
            } else if (idx > 0) {
                var itemToMove = $scope.peoples.splice(idx, 1)
                console.log(itemToMove[0])
                $scope.peoples.splice(idx-1, 0, itemToMove[0]);

            }
        }
    };
Run Code Online (Sandbox Code Playgroud)

(希望)最终演示

编辑: 我很喜欢这个问题,并希望有一个更好的解决方案,以防有重复的列表项.通过为数组中的每个对象提供唯一的id键,然后更改track by item.nametrack by item.id,并且所有工作都像以前一样工作,这很容易解决.

重复的工作演示


pix*_*its 5

演示

您需要更新您的swapIf实现,以便交换模型,而不是视图中的选项:

function swapIf(sel,i1,i2) {
    if ( ! select[i1].selected && select[i2].selected) {

        var obj1 = $scope.peoples[i1];
        var obj2 = $scope.peoples[i2];
        $scope.peoples[i2] = obj1;
        $scope.peoples[i1] = obj2;
        select[i1].selected = true;
        select[i2].selected = false;
    }
}
Run Code Online (Sandbox Code Playgroud)

此外,删除orderBy视图中的,并使用该$filter服务初始化控制器中的顺序.您需要这样做的原因是,只要用户单击向上/向下按钮,就会重新排序列表.