2015-04-18 32 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

相關問題