Tropicalista Tropicalista - 5 months ago 29
AngularJS Question

AngularJs get count of element by class name

How can I count element by class name in angularJs?

I have tried with:

$scope.numItems = function() {
$window.document.getElementsByClassName("yellow").length;
};


Plunkr: http://plnkr.co/edit/ndCqpZaALfOEiYieepcn?p=preview

Answer

You have defined your function correctly, but made a mistake in showing its results: it should have been...

<p>{{numItems()}}</p>

... instead of plain {{numItems}}. You want to display the return value of the function, and not the function itself (that's meaningless), that's why you should follow the standard JS syntax for a function invocation.

Note that you can send arguments into this expression too: for example, I've rewritten that method like this:

$scope.numItems = function(className) {
   return $window.document.getElementsByClassName(className).length;
};

... and then made three different counters in the template:

  <p>Yellow: {{numItems('yellow')}}</p>
  <p>Green: {{numItems('green')}}</p>
  <p>Red: {{numItems('red')}}</p>

Plunker Demo.


But here's the real problem: numItems() result, used in one View, is based on DOM traversal - in other words, on another View. Not only that goes against Angular philosophy in general, it tends to break. In fact, it DOES break since this commit, as old as 1.3.0:

Now, even when the ngAnimate module is not used, if $rootScope is in the midst of a digest, class manipulation is deferred. This helps reduce jank in browsers such as IE11.

See, changes in classes are applied after digest - and that's after numItems() is evaluated, hence the delay in demo mentioned by @Thirumalaimurugan.

A quick-and-dirty solution is using another attribute for selector in numItems (in this plunker, it's data-color). But I would strongly advise you against it. The proper approach would be adding the data rendered by numItems() -using component into the model. For example:

app.js

// ...
var colorScheme = {
  'toggle':  {true: 'yellow', false: 'red'},
  'toggle2': {true: 'green', false: 'red'},
  'toggle3': {true: 'green', false: 'red'},
  'toggle4': {true: 'red', false: 'green'}
};

$scope.getColor = function getColor(param) {
  return colorScheme[param][$scope[param]];
};

$scope.countColor = function(color) {
  return Object.keys(colorScheme).filter(function(key) {
    return colorScheme[key][$scope[key]] === color;
  }).length;
};

index.html

<p ng-class="getColor('toggle')">{{name}}</p>
<!-- ... -->

<p ng-repeat="color in ['Yellow', 'Green', 'Red']" 
   ng-bind="color + ' ' + countColor(color.toLowerCase())">

Demo.

Comments