NewGuy504
NewGuy504

Reputation: 143

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

TLDR: What I'm trying to achieve: IF there is a office.vote present (if it exist), then filter by office.vote.candidateId. Else, order by 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}}

I realize My attempt to combine the orderby and filter above will not work. I'm not extremely familiar with custom filters. How could I achieve what I'm trying to do with a custom filter?

I think my issue is with candiateProfiles being an array..

here is the object in scope:

enter image description here


failed attempt 2:

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

controller:

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

in the controller above, this works for filtering by office.vote, but I need a new way for the 'else' to filter by highest vScore. I don't think it's recognizing candiateProfiles, because it's an array.

Upvotes: 2

Views: 5450

Answers (1)

ilmgb
ilmgb

Reputation: 770

Okay. After some clarification let us give it a try. See this working Plnkr

I am using two different ng-repeats to match either one or the other case.

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

Case 2: "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>

The filtering happens inside a small function:

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

I hope this is what you have been looking for. In general it would be nice if you could prepare a small plnkr with minimal data (like I did) to get a better understanding of your problem.

In general I guess it could be simplified further to have only one ng-repeat and have a filter function that checks first, if the vote is set, and if - it calls the isOfficeIdMatching function as well.

Edit: to check the results of both cases remove the vote object inside the JSON object. See LoC 36-38 in app.js

//remove the vote object, to see another output.
vote: {
  officeId: 8
}

Edit 2: To have the simplified solution: Simplified Plnkr (no ng-if's due to OP's comment)

There is no ng-if anymore. And the isVoteSet function takes care of checking if the officeId's match. If no vote is set it just returns true.

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

The new parent function:

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

Edit 3:

As your use case is the following.

A) If a vote is set, filter all the candidateProfiles to match the one that has been voted

B) If no vote is set, just order the list by the vScore

Here the final solution to your problem: 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
    }

  };
});

Upvotes: 1

Related Questions