18

I am showing subsets of a list if a checkbox is checked. I would like to replace the X next to the checkbox with the count of the list matching the selection criteria. I have a plunker that does everything but count the subset here.

My Controller looks like this:

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

app.controller('MainController', function($scope){
  $scope.cbMarvel = true;
  $scope.cbDCComics = true;

  $scope.heroes = [
    {
      id: 1,
      name: 'Iron Man',
      fname: 'Tony',
      lname: 'Stark',
      location: 'Stark Tower',
      comic: 'Marvel'
    },
    {
      id: 2,
      name: 'Batman',
      fname: 'Bruce',
      lname: 'Wayne',
      location: 'Bat Cave',
      comic: 'DC'
    },
    {
      id: 3,
      name: 'Superman',
      fname: 'Clark',
      lname: 'Kent',
      location: 'Metroplis',
      comic: 'DC'
    },
    {
      id: 1,
      name: 'Daredevil',
      fname: 'Jack',
      lname: 'Murdock',
      location: 'Court Room',
      comic: 'Marvel'
    },
    {
      id: 5,
      name: 'Flash',
      fname: 'Barry',
      lname: 'Allen',
      location: 'Speedline',
      comic: 'DC'
    },
    {
      id: 6,
      name: 'Hulk',
      fname: 'Bruce',
      lname: 'Banner',
      location: 'Labratory',
      comic: 'Marvel'
    },
    {
      id: 7,
      name: 'Hawkeye',
      fname: 'Clint',
      lname: 'Barton',
      location: 'Nest',
      comic: 'Marvel'
    },
    {
      id: 8,
      name: 'Thor',
      fname: 'Donald',
      lname: 'Blake',
      location: 'Asgard',
      comic: 'Marvel'
    }
  ];
});

And my view looks like this:

<!DOCTYPE html>
<html ng-app="app">
  <head>
    <link data-require="bootstrap@*" data-semver="3.2.0" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.css" />
    <link data-require="bootstrap-css@*" data-semver="3.2.0" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" />
    <script data-require="bootstrap@*" data-semver="3.2.0" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.js"></script>
    <script data-require="[email protected] current" data-semver="2.0.3" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
    <script data-require="[email protected]" data-semver="1.2.20" src="https://code.angularjs.org/1.2.20/angular.js"></script>
    <script data-require="angular-ui-bootstrap@*" data-semver="0.11.0" src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.11.0.min.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body ng-controller="MainController">
     <fieldset>
        <legend>Comments Log</legend>
        <div class="row">
            <div class="col-md-4">
                <input type="checkbox" ng-model="cbMarvel"/> Marvel [X]
            </div>
            <div class="col-md-4">&nbsp;</div>
            <div class="col-md-4">
                <input type="checkbox" ng-model="cbDCComics"/> DC Comics [X]
            </div>
        </div>

        <div class="row">&nbsp;</div>

        <div class="row col-md-10">
            <div ng-if="heroes.length == 0"><b>No Heroes Found!</b>
            </div>
            <div ng-repeat="h in heroes | filter:{comic:'Marvel'}" ng-show="cbMarvel">
                {{ h.name}} - {{h.comic}}
            </div>
            <div ng-repeat="h in heroes | filter:{comic:'DC'}" ng-show="cbDCComics">
              {{ h.name}} - {{h.comic}}
            </div>
        </div>
    </fieldset>
  </body>

</html>
1
  • 6
    Daredevil is Matt Murdock, not Jack. Jack is Daredevil's dead father. (Oh Lord, I'm such a geek. I need professional help.) Commented Oct 28, 2015 at 17:16

4 Answers 4

28

Assuming your list of people is in data variable and you filter people using query model, the following code will work for you:

  • Number of visible people: {{(data|filter:query).length}}
  • Total number of people: {{data.length}}

summary

{{data.length}} - prints total number of people

{{(data|filter:query).length}} - prints filtered number of people

Sign up to request clarification or add additional context in comments.

1 Comment

i am very glad that my solution worked for you guys , thanks for ur support
16

You could set that count in the view model itself while binding the data or just have a method on the scope that returns the count.

app.controller('MainController', function($scope, filterFilter){
   ....
    $scope.getCount = function(strCat){
      return filterFilter( $scope.heroes, {comic:strCat}).length;
    }
    ...
});

and use it as:-

  Marvel [{{getCount("Marvel")}}]
  .....
  DC Comics [{{getCount("DC")}}]

Plnkr

If the list is non changing when you are on the page i would suggest finding out the length and binding it to a property in the view model itself, and use it in the view.

 //Set your data model
  $scope.cbMarvel = {value:true, count:getCount('Marvel')};
  $scope.cbDCComics = {value:true, count:getCount('DC')};

and in your view

   <input type="checkbox" ng-model="cbMarvel.value"/> Marvel [{{cbMarvel.count}}]

Plnkr2

If your dataset is huge, instead of using filter inside the getCount, use a forEach and populate the count for each type at once.


Infact you do not need a filter at all, it seems inefficient to iterate through the same list using a filter in your case. Your's is a static list so categorize it in the controller itself.

var comics = $scope.comics  = {}; //Dictionary of comics
  //Create the collection here.
  angular.forEach(heroes, function(itm){
    if(!comics[itm.comic]){
     comics[itm.comic] = {name:itm.comic, value:true, count:1, items:[itm] };
     return;
    }

    comics[itm.comic].count++; //Incr count
    comics[itm.comic].items.push(itm); //push specific item
  });

and remove all the filters in your view and do:-

    <div ng-repeat="h in comics.Marvel.items" ng-show="comics.Marvel.value">
        {{ h.name}} - {{h.comic}}
    </div>
    <div ng-repeat="h in comics.DC.items" ng-show="comics.DC.value">
      {{ h.name}} - {{h.comic}}
    </div>

Plnk3 - the better one

Comments

15

Possible solution 1: Inline

You could actually save a reference to the filtered results in a variable: h in filtered.marvel = (heroes | filter:{comic:'Marvel'}), which you could use like so: filtered.marvel.length.

See: Plunkr

Possible solution 2: In the controller

You could also move this code to your controller:

$scope.filteredHeroes.marvel = $filter('filter')($scope.heroes, {comic:'Marvel'});

, which you could use by ng-repeat="hero in filteredHeroes.marvel"

and {{filteredHeroes.marvel.length}}

(Don't forget to add $filter as a controller dependency)

See: Plunkr

2 Comments

It is really bad and inefficient to do a filter when there is no need to to use a filter.
How to do if multiple filter fields with OR condition??
0

To find the count objects, I use <scope_obj>.length in the .html template.

Here's my controller:

conciergeControllers.controller('GuestMsgPreviewCtrl', ['$scope', 'GuestMessages',
    function($scope, GuestMessages) {
    $scope.guests = GuestMessages.query();
}]);

And template (each guest object has a messages attribute that is an array object, so .length returns the number of nested message objects:

<ul ng-repeat="guest in guests">
  <li>[[ guest.messages.length ]]</li>
</ul>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.