【问题标题】:Issue with Angularjs Dropdown and a custom filterAngularjs Dropdown 和自定义过滤器的问题
【发布时间】:2014-10-04 17:09:55
【问题描述】:

我在使用填充有 ng-repeat 选项值的下拉菜单时遇到问题,甚至在使用 ng-options 时也遇到了问题。

基本上,我是从数据库中提取子公司列表。然后,我有一个下拉列表来选择一家公司,而该公司又应使用所选公司的子公司填充子公司下拉列表。由于许多子公司属于同一家公司,如果我尝试在 ng-repeat 中提取公司名称,我会多次获得同一家公司。所以我创建了一个自定义过滤器,它只过滤掉列出的每家公司的 companyName 和 companyID 一次。

理论上,当我更改公司下拉列表的值时,会列出正确的子公司。但是,公司框中显示的值停留在列出的第一个选项上并且不会改变。如果我删除自定义过滤器并允许它列出所有重复名称,则该框将正确显示。

我的第一个想法是进行单独的 HTTP 调用,它只会从我的公司表中获取公司,但我想我想将 HTTP 调用限制为尽可能少。另外,我似乎应该能够做到这一点。

当我使用过滤器时,我没有掌握什么概念会阻止它正确显示,我应该怎么做才能解决这个问题? 谢谢

HTML:

<div class="col-sm-5">
   <select ng-model ="parentCompany" name="company">
      <option ng-repeat="company in companies | uniqueCompanies:'companyName'" value="{{company.id}}" >{{company.name}}</option>
    </select>                                                 
</div>

<div class="col-sm-5">
   <select name="subsidiary">
    <option ng-repeat="subsidary in companies" value="{{subsidary.subID}}" ng-hide="$parent.parentCompany !== subsidary.companyID">{{subsidary.subName}}</option>
   </select>
</div>

控制器:

  getCompanies();
            function getCompanies(){
                 $http.get("get.php?table=getcompanies").success(function(data) {
                    $scope.companies = data;
                });
            }

过滤器:

.filter("uniqueCompanies", function() {
            return function(data, propertyName) {
                if (angular.isArray(data) && angular.isString(propertyName)) {
                    var results = [];
                    var keys = {};
                    for (var i = 0; i < data.length; i++) {
                        var val = data[i][propertyName];
                        var val2 = data[i]['companyID'];
                        if (angular.isUndefined(keys[val])) {
                            keys[val] = true;
                            results.push({'name':val, 'id':val2});
                        }
                    }
                    return results;
                } else {
                    return data;
                }
            };
        });

样本数据:

[{"subID":null,"subName":null,"companyID":"1","companyName":"DWG"},
 {"subID":null,"subName":null,"companyID":"2","companyName":"Vista"},
 {"subID":"1008","subName":"Data Services","companyID":"3","companyName":"Medcare"},
 {"subID":"1009","subName":"Companion","companyID":"3","companyName":"Medcare"},
 {"subID":"1010","subName":"GBA","companyID":"3","companyName":"Medcare"},
 {"subID":"1011","subName":"PGBA","companyID":"3","companyName":"Medcare"},
 {"subID":"1013","subName":"Health Plan","companyID":"3","companyName":"Medcare"},
 {"subID":"1014","subName":"PAISC","companyID":"3","companyName":"Medcare"},
 {"subID":"1015","subName":"CGS","companyID":"3","companyName":"Medcare"}]

【问题讨论】:

  • 在选择之前在控制器中运行过滤器会有帮助吗?
  • 因为过滤器每次都返回一个新对象数组,所以您需要提供一个track by 表达式。看看这是否有所作为。
  • 你能给一些示例数据吗?这有点难以理解,因为您在过滤器中重命名了属性。看起来您的数据包含 companyNamecompanyIDsubIDsubName。如果子公司拥有自己的子公司,规则是什么?即“GE->NBC Universal->NBC 广播”?
  • @Dylan - 我之前没有在控制器中使用过过滤器。但是根据您的建议,我只是尝试将 $filter 添加到我的控制器,然后通过 $scope.oldCo = $filter('uniqueCompanies')($scope.companies, 'companyName') 过滤但是 $scope.oldCo 是空的。我做错了吗?
  • @AndyMcCormick 喜欢这样的作品 - jsfiddle.net/devitate/zfx6sbdf

标签: angularjs angularjs-ng-repeat angularjs-filter


【解决方案1】:

您正在过滤器中创建具有不同属性的新对象,因此它们每次都会有所不同。你可以像其他人提到的那样track by。由于过滤器执行every digest cycle,您可能希望设置$watch,并且仅在您的公司发生变化时创建一个新的唯一公司列表。我实际上没有这样做就得到了10 $digest() iterations reached 错误。

$scope.$watchCollection('companies', function(newValue) {
    $scope.filteredCompanies = $filter('uniqueCompanies')($scope.companies, 
        'companyName');
});

您还可以在parentCompany 上设置监视并仅在其更改时创建子公司列表,并清除您对subvisoryCompany 的值:

$scope.$watch('parentCompany', function(newValue) {
  $scope.subsidiaries = [];
  for (var i = 0; i < $scope.companies.length; i++) {
    var c = $scope.companies[i];
    if (c.companyID === newValue) {
      $scope.subsidiaries.push(c);
    }
  }
  $scope.subsidiaryCompany = undefined;
});

【讨论】:

  • 谢谢!我担心10 $digest() iterations reached 错误,但是我发现在网上谈论它的大多数地方似乎都有“忽略它”的想法。我尝试在小提琴中添加手表并且它有效,但是我的代码中似乎存在另一个问题,因为 Dylan 链接到的小提琴工作正常,但在我的实际应用程序中不起作用。当我可以正式说它解决了问题时,我会回来并将其标记为最佳答案。谢谢
  • 明白了!这很好用,并且确实摆脱了迭代达到的错误。我一直想花一点时间来了解观察者是如何工作的,这很好地迫使我了解何时、何地以及为什么使用它们。谢谢!
  • 很高兴它成功了。如果您正在学习,请注意 $watch$watchCollection 之间的 differences。手表比较也是每隔$digest 进行的,如果不修改它们,最好在getCompanies() 函数中设置uniqueCompanies。由于您也在创建新对象,$watchCollection 不会捕捉到对象属性的差异,例如,如果您更改公司名称。
【解决方案2】:

我可能不完全理解您的问题,但看起来您可以在获得数据时对其进行过滤。比如……

function getCompanies(){
  $http.get("get.php?table=getcompanies").success(function(data) {
    $scope.companies = data.reduce(function (prev, cur) {
      // some code for skipping duplicates goes here                              
    }, []);
  });
}

Array.reduce 可能不是获得没有重复的新数组的最佳方法,但无论如何,这是一般的想法。

【讨论】:

  • 感谢您的回复。当我得到我的数据时过滤不起作用,因为我仍然需要所有子公司,无论它们的母公司是什么。我想我可以将 $scope.companies 转储到一个数组中并减少它,然后从中提取我的公司列表,但这似乎绕过并破坏了使用 Angularjs 的目的。
猜你喜欢
  • 2013-11-29
  • 1970-01-01
  • 2013-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多