如何在 ng-repeat 中按 orderby 或其他过滤条件有条件地过滤?

How to conditionally filter by orderby or another filter criteria in an ng-repeat?

TLDR:我想要实现的目标: 如果存在 office.vote(如果存在),则按 office.vote 过滤。 candidateId.否则,按 office.candiateProfiles.vScore

排序
.offices(ng-repeat='office in service.offices' ng-class="{'last':$last}")
          .row.row-format.text-uppercase
            .office.ballot(ng-click='showCandidates = !showCandidates')
              .col-xs-7.col-sm-4.col-md-4.mainBallot-col
                .office-name
                  {{office.name}}
              .col-xs-5.col-sm-8.col-md-8.border-left.mainBallot-col
                .ballot(ng-repeat="candidate in office.candidateProfiles | orderBy: '-vScore' | filter: office.vote.candidateId | limitTo: 1 | " )
                  .row.noPad
                    .col-xs-1.col-sm-1.col-md-1.straight-col.ballotCheck-col
                    .col-xs-7.col-sm-7.col-md-7.straight-col.highest-col
                      %table.highestShow
                        %tr
                          %td
                            .vs
                              {{candidate.fullName}}

我意识到我尝试结合上面的 orderby 和 filter 是行不通的。我对自定义过滤器不是很熟悉。我怎样才能实现我想用自定义过滤器做的事情?

我认为我的问题是 candiateProfiles 是一个数组。

这是范围内的对象:


失败的尝试 2:

                .ballot(ng-repeat="candidate in office.candidateProfiles | filter:criteriaMatch(office) | limitTo:1" )

控制器:

$scope.criteriaMatch = function(office) {
  console.log(office);
  if (office.vote) {
    return office.vote.candidateId;
  } else {
    return orderBy(office.candidateProfiles.vScore)
  }
};

在上面的控制器中,这适用于按 office.vote 过滤,但我需要一种新方法让 'else' 按最高 vScore 过滤。我认为它不能识别 candiateProfiles,因为它是一个数组。

好的。在澄清之后让我们试一试。看到这个 working Plnkr

我正在使用两种不同的 ng-repeats 来匹配一种或另一种情况。

案例 1 "No Vote set":

    <!-- in case there is no vote -->
    <div ng-if="main.office.vote == null">
      No Vote set, show all candidates, orderedBy '-vScore'
      <div ng-repeat="candidate in main.office.candidateProfiles | orderBy:'-vScore'">
        {{candidate.fullName}}
      </div>
    </div>

案例二:"Vote set"

    <!-- in case there is a vote -->
    <div ng-if="main.office.vote != null">
      Vote set: only show candidates matching the office, orderedBy '-vScore'
      <div ng-repeat="candidate in main.office.candidateProfiles | filter:main.isOfficeIdMatching | orderBy:'-vScore'">
        {{candidate.fullName}}
      </div>
    </div>

过滤发生在一个小函数内:

  vm.isOfficeIdMatching = function(candidate) {
    return vm.office.vote.officeId ==  candidate.officeId;
  }

希望这就是您一直在寻找的。一般来说,如果你能用最少的数据准备一个小的 plnkr(就像我做的那样)来更好地理解你的问题,那就太好了。

总的来说,我想它可以进一步简化为只有一个 ng-repeat 并有一个过滤器函数,首先检查是否设置了投票,如果 - 它也调用 isOfficeIdMatching 函数.

编辑: 要检查这两种情况的结果,请删除 JSON 对象中的投票对象。 参见 app.js

中的 LoC 36-38
//remove the vote object, to see another output.
vote: {
  officeId: 8
}

编辑 2: 要获得简化的解决方案:Simplified Plnkr(由于 OP 的评论,没有 ng-if)

没有 ng-if 了。 isVoteSet 函数负责检查 officeId 是否匹配。如果没有设置投票,它只是 returns true。

  <div ng-repeat="candidate in main.office.candidateProfiles | filter:main.isVoteSet | orderBy:'-vScore'">
      {{candidate.fullName}}
    </div>

新的父函数:

     vm.isVoteSet = function(candidate) {
        if(vm.office.vote != null) {
          return vm.isOfficeIdMatching(candidate);
        }
        return true;
      }

编辑 3:

因为您的用例如下。

A) 如果设置了投票,过滤所有 candidateProfiles 以匹配已投票的人

B) 如果没有设置投票,就按vScore排序列表

这里是您问题的最终解决方案:Final Plnkr

HTML

<div ng-repeat="candidate in main.office.candidateProfiles| filter:main.isVoteSet | orderBy:main.whichOrderByPredicate">
      <label>
        <input type="checkbox" ng-click="main.setVote(candidate)"/>
        {{candidate.fullName}}
      </label>
    </div>

JS

    var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {

  var vm = this;

  vm.office = {
    name: "Metro Mayer",
    candidateProfiles: [
      {
        candidateId: 5,
        fullName: "John (Id 15, Score 1)",
        vScore: 1
      },
      {
        candidateId: 8,
        fullName: "Linda (Id 8, Score 3)",
        vScore: 3
      },
      {
        candidateId: 120,
        fullName: "Ben (Id 120, Score 2)",
        vScore: 2
      },
      {
        candidateId: 14,
        fullName: "Rick (Id 14, Score 1)",
        vScore: 1
      },
      {
        candidateId: 15,
        fullName: "Tesla (Id 15, Score 2)",
        vScore: 2
      }
    ],
    vote: {}
  };

  /*Filtering functions

    only used if a vote is set
  */

  vm.isVoteSet = function(candidate) {
    if(JSON.stringify(vm.office.vote) != "{}") {
      return vm.isCandidateIdMatching(candidate);
    }
    return true;
  };

  vm.isCandidateIdMatching = function(candidate) {
    return vm.office.vote.candidateId == candidate.candidateId;
  };

  /*Ordering functions

    only used if NO vote is set
  */

  vm.whichOrderByPredicate = function(candidate) {
    return JSON.stringify(vm.office.vote) == "{}" ? -candidate.vScore : null;
  };

  /* Application logic */

  vm.setVote = function(candidate) {
    //unset if already set
    if(vm.office.vote.candidateId == candidate.candidateId) {
      vm.office.vote = {};
    }
    //else set the vote
    else {
      vm.office.vote.candidateId = candidate.candidateId
    }

  };
});