Angular ngRepeat 多个 select 字段而不显示已通过 ng-options selected 的数据

Angular ngRepeat multiple select fields without displaying already selected data through ng-options

所以问题的概述;我正在从 api 中检索数据并为其创建一个 CRUD 页面。数据有一组标签,用户可以 select.

下面是代表我的问题的代码示例。用户 selected 的标签由 user.labels 关系表示,可以 selected 的总可用标签由 user.parent.grandparent.labels.

表示

我可以同步 selection。我似乎无法弄清楚的是如何从任何其他后续 select 字段的选项列表中删除已经 selected 的选项。

angular.module('app', [])
  .controller('select', ['$scope', '$filter', '$location',
    function($scope, $filter, $location) {
      $scope.user = {
        "parent": {
          "grandparent": {
            "labels": [{
              "id": 28,
              "name": "Label 1",
            }, {
              "id": 17,
              "name": "Label 2",
            }, {
              "id": 39,
              "name": "Label 3",
            }, {
              "id": 77,
              "name": "Label 4"
            }, {
              "id": 100,
              "name": "Label 5"
            }]
          }
        },
        "labels": [{
          "id": 28,
          "name": "Label 1",
          "meta": {
            "score": 3
          }
        }, {
          "id": 17,
          "name": "Label 2",
          "meta": {
            "score": 5
          }
        }]
      };
    }
  ]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app="app" ng-controller="select">
  <div ng-repeat="label in user.labels track by $index">
    <div class="form-field">
      <span>Label</span>
      <select ng-model="user.labels[$index]" ng-options="department.name for department 
                        in user.parent.grandparent.labels track by department.id">
      </select>
    </div>
    <div>
      <span>Score</span>
      <select ng-model="label.meta.score">
        <option value="1">1 (lowest)</option>
        <option value="2">2</option>
        <option value="3">3</option>
        <option value="4">4</option>
        <option value="5">5 (highest)</option>
      </select>
    </div>
  </div>
  <button ng-click="user.labels.push({})">Add Label</button>
</div>

您可以在 ng-repeat 中使用过滤器函数来实现这一点,这里有一个示例 Codepen 向您展示了如何操作:

http://codepen.io/anon/pen/ZYveOo

您需要在重复定义中传递过滤器:

<select ng-model="user.labels[$index]" ng-options="department.name for department in user.parent.grandparent.labels | filter:removeSelected track by department.id ">

在范围内引用此函数:

      $scope.removeSelected = function(val){
        return !_.find($scope.user.labels, function(label) {
          return label.id === val.id;
        });
      };

尽管如此,我认为您遗漏了一个用例,即您希望能够将当前选定的标签包含在选项中,但通过删除所有选定的选项,您将删除该功能。

更新:

那么好吧,经过一番思考后,我想出了以下可以优化但似乎确实按预期工作的过滤器:

.filter('duplicatesFilter', function() {
        return function(items, index, selected) { 
          var res = [selected[index]];
          _.forEach(items, function(item){
            if(!_.find(selected, function(label) {
              return label.id === item.id;
            })){
              res.push(item);
            }
          });

          return res;
        };
    })

像这样使用它:

<select ng-model="user.labels[$index]" ng-options="department.name for department in user.parent.grandparent.labels | duplicatesFilter:$index:user.labels track by department.id "></select>

这是我遇到过几次并且每次都解决它的问题。如果我能找到更好地解决问题的自定义过滤器,我稍后会看一下,如果找不到,我会整理这段代码并发布一个;然而,这应该适合您的用例。

工作码笔:

http://codepen.io/anon/pen/ZYveOo