【问题标题】:How to conditionally filter by orderby or another filter criteria in an ng-repeat?如何在 ng-repeat 中按 orderby 或其他过滤条件有条件地过滤?
【发布时间】:2015-07-29 14:00:56
【问题描述】:

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,因为它是一个数组。

【问题讨论】:

  • 我不太清楚这个问题。您能否尝试更具体地说明您的逻辑,甚至更好:为此创建一个小 plnkr? Angular 1.4 的模板plnkr.co/edit/tpl:8rFfZljYNl3z1A4LKSL2
  • 我试图弄清楚我想要实现的目标。
  • @limgb,是不是更清楚了?
  • 是的。但是:目前尚不清楚为什么要过滤一种情况而只过滤另一种情况。是否有触发过滤的输入?
  • 有一个复选框可以创建 office.vote。在您单击候选人旁边的框之前,它不存在。在创建之前,我想根据分数显示最高结果。创建后,选定的候选人 (office.vote.candidateId) 会用分数替换默认过滤器。

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


【解决方案1】:

好的。经过一些澄清后,让我们试一试。看到这个working Plnkr

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

案例1“没有投票”:

    <!-- 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>

案例 2:“投票集”

    <!-- 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 是否匹配。如果没有设置投票,它只会返回 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) 如果设置了投票,则过滤所有候选配置文件以匹配已投票的配置文件

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
    }

  };
});

【讨论】:

  • 这与我之前提出的类似,使用 2 ng-ifs,我同意必须有一个简化的过滤器(DRY),这就是我想要的弄清楚。我无法弄清楚如何在上面的条件内按 office.candidateProfiles.vScore 过滤/排序,我确定这很明显我错过了。
猜你喜欢
  • 1970-01-01
  • 2013-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-21
  • 2015-06-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多