2015-04-18 31 views
4

我已经创建了一个angularjs应用程序与多个选择上我有上下按钮,其中当我单击向上和向下按钮相应的项目移动应完成内多重选择,我已经与普通的JavaScript该做类似的事情做得正确像如本fiddle样本的东西,但是当我试图实现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> 

脚本

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; 
     } 
    } 
}); 
+0

可能是'排序依据:'name''引起的问题 –

+0

@pankajparkar我们能用不同的方法,而无需使用'document.getElementById'做到这一点,你对这个 –

+1

该控制器的任何想法代码是不好的角度练习。 DOM操作应该通过指令来完成,而不是控制器。 – tpie

回答

7

persons将返回列表中所选项目的数组。一种解决方案是创建一个for循环,获取persons阵列中每个项目的indexOfsplice表示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]); 

      } 
     } 
    }; 

这里是更新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]); 

      } 
     } 
    };  

这里是Working Demo(不工作这么好,只是保留以供参考 - 见下)

该解决方案还保持View和Contro之间的分离米勒。控制器具有处理数据的工作,视图显示该数据。这样我们可以避免任何不可避免的纠缠。控制器内的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时,它会按顺序返回项目,但是如果您尝试遍历数组,将每个项目向下移动,则可能会影响阵列中其他项目的位置(进一步产生不可预知的行为)。所以我们需要从底部开始,在向下移动多个项目时继续前进。

这里是我似乎已经消除了任何不可预知的行为使多个任意选择时的解决方案:

Working Demo

编辑: 一个错误,我发现是奇怪的事情发生,你的时候将多个选定的项目向上或向下移动,然后尝试再次将其移向该方向。任何进一步的移动都不会产生不可预知的结果。

编辑: 上一个编辑提到的不可预知的行为是因为功能正在看到的是,虽然第一个项目是在它的最后位置,第二,第三,第四等项目​​是不是结束位置,因此它试图移动它们,这导致疯狂地重新排序已经将所有项目推到顶部或底部的项目。为了解决这个问题,我设置了一个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]); 

      } 
     } 
    }; 

(希望)Final Demo

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

Working Demo for Duplicates

+0

你的解决方案有效,但有一个问题是,我选择'Lenu'和'Ferix',然后点击向上按钮,当他们到达顶部时,'Lenu'作为第一个位置,'Ferix'作为第二个位置,同样,如果我们点击向上按钮,顺序变为'Ferix'作为第一个位置,'Lenu'作为第二个位置,同样在初始选择所有选项并单击向上按钮,您可以看到一些意外的顺序发生 –

+0

是的,我也注意到了这一点。这是因为函数的工作方式,它获取任何选定项目的位置,并减少索引。在选择多个或两个项目并向下移动时,我也发现了一些奇怪的行为。正在处理它... – tpie

+0

任何针对该问题的解决方案@tpie,我也尝试从我身边......但没有通过 –

5

Demo

您需要更新您的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; 
    } 
} 

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

+0

它的工作单选,但似乎没有多个值选择工作 –

+0

再试一次 - 我已经修复了。 – pixelbits

+0

这不是角度的方式。 – tpie

相关问题