AngularUI:使用过滤器正确更新两个列表之间的模型

时间:2013-09-28 23:12:54

标签: javascript html jquery-ui angularjs jquery-ui-sortable

我在AngularUI中使用Sortable来管理多个可排序列表。我已经开始工作,我可以在列表之间轻松移动项目,并相应地更新相应的模型。但是,如果我包含查询过滤器,如果发生以下情况,我会遇到一些问题:

  1. 用户输入的搜索字段不是列表的第一个条目。
  2. 用户将过滤结果中的第一项从一个列表移动到另一个列表。
  3. 似乎有效,直到查询被清除并显示初始列表。虽然您在应用查询时似乎移动了条目,但您会注意到在清除之后,未移过的数组中的第一个条目被移动了。
  4. 在您进行拖放时,似乎Sortable不会考虑过滤器。这是相关的HTML:

      <p>Search: <input ng-model="query" /></p>
      <div class="column-wrapper">
        <ul ui-sortable="sortableTemplates" ng-model="list1" id="sortable1" class="connectedSortable">
          <li ng-repeat="item in list1|filter:query" class="itemBox">{{item.name}}</li>
        </ul>
        <ul ui-sortable="sortableTemplates" ng-model="list2" id="sortable2" class="connectedSortable">
          <li ng-repeat="item in list2|filter:query" class="itemBox">{{item.name}}</li>
        </ul>
      </div>
    

    和相应的JS:

    var app = angular.module('myApp', ['ui.sortable']);
    app.controller('test', function($scope) {
    
    $scope.list1 = [
        {name: 'ABC'},
        {name: 'DEF'},
        {name: 'GHI'}
    ];
    
    $scope.list2 = [
        {name: 'JKL'},
        {name: 'MNO'},
        {name: 'QRS'}
    ];
    
    $scope.sortableTemplates = {
        connectWith: '.connectedSortable'
    }
    

    });

    Here it is running on Plunker.

    要复制问题,您可以尝试搜索GHI,然后将GHI移至list2。然后,清除搜索框。 ABC实际上是移动到list2的那个(因为它是该数组中的第一个元素),而GHI仍然在列表一中。

    有没有办法让Angable过滤器具有可排序性,以便在列表之间进行排序时保留原始索引?

    (我刚开始使用Angular和JQueryUI,所以答案可能非常明显。我发现了类似的问题,但似乎并没有直接解决这个问题。)

1 个答案:

答案 0 :(得分:3)

正如你所说,ui-sortable使用元素索引在列表之间移动它,这样当你移动过滤列表中的第一个项目时,它会移动原始列表中的第一个项目。 解决这个问题的一种方法是过滤列表,而不是隐藏您不想移动的项目,而不是像ng-repeat中的过滤器那样创建新列表。 所以在你的HTML中:

<li ng-repeat="item in list1" class="itemBox" ng-show="visible(item)">{{item.name}}</li>

ng-show将显示或隐藏元素,具体取决于$ scope.visible(item)是返回true还是false。 因此,我们在控制器中创建一个函数,如果我们想要查看元素,即它没有被过滤掉,则返回true,如果它被过滤掉则返回false。

$scope.visible=function(item){
  //create an array containing all of the elements in both lists
  var lists=$scope.list1.concat($scope.list2);
  // filter this list using our search term
  var filteredItems=$filter('filter')(lists, $scope.query);
  //if there are no matching items left in our list then return false
  if (filteredItems.length===0){return false;}
  //see if the current item is in the filtered list   
  if (($filter('filter')(filteredItems,item)).length===1){
     return true;
  } else {
     return false;
  }
}

我在http://plnkr.co/edit/JCQdcP?p=preview

创建了一个plunker