0

In angular JS, I have a variable that keeps track of people and their age

$scope.people = [
    {
        name: "Lucy",
        age: "18"
    }, {
        name: "Michael",
        age: "24"
    }, {
        name: "Lisa",
        age: "46"
    }
];

The user can add more people via a simple form:

<input ng-model="newPerson.name">
<input ng-model="newPerson.age">
<button ng-click="addNewPerson()">Add</button>

At the bottom of the page, I want a simple pie graph showing the population by age group eg.(>18, 18-25, 26-35, 36-45, 45<). To do that, I need to be able to filter the $scope.people by age, get the number of each group.

I know I could use normal javascript to loop through the whole array, get a count of each age group. And whenever a new person is added, just increment the count in that particular group, but I was wondering if there is a more efficient and angular-esque way to do this?

2 Answers 2

1

Here's one way to implement this with Array.Prototype.filter and Array.Prototype.reduce. Note the the filter is applied on $scope.ageBrackets which contains the pre-processed data prepared by the forEach loop. This is efficient for small range values such as the age of a person. This is one alternative if you are not using ng-repeat and you don't want to filter the data multiple times.

angular.module('ageBracketApp', ['ageBracketApp.controllers']);
angular.module('ageBracketApp.controllers', []).controller('ageBracketController', ['$scope',
  function($scope) {

    $scope.ageBrackets = [];

    $scope.people = [{
      name: "Lucy",
      age: "18"
    }, {
      name: "Michael",
      age: "24"
    }, {
      name: "Lisa",
      age: "46"
    }];

    angular.forEach($scope.people, function(value, key) {
      $scope.ageBrackets[value.age] = $scope.ageBrackets[value.age] + 1 || 1;
    });

    $scope.addPerson = function() {
      var age = Math.floor(Math.random() * (123 - 1 + 1)) + 1; // random between 1 and 123
      $scope.people.push({
        name: 'Person ' + ($scope.people.length + 1),
        age: age
      });
      $scope.ageBrackets[age] = $scope.ageBrackets[age] + 1 || 1;

    };

    $scope.ageBracketCount = function(min, max) {
      max = max || Number.MAX_SAFE_INTEGER;
      return $scope.ageBrackets.filter(function(value, index, array) {
        return index >= min && index <= max;
      }).reduce(function(a, b) {
        return a + b;
      }, 0);
    };
  }
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="ageBracketApp" ng-controller="ageBracketController">
  {{people}}
  <hr />18+: {{ageBracketCount(18)}}
  <br />18-25: {{ageBracketCount(18,25)}}
  <br />26-35: {{ageBracketCount(26,35)}}
  <br />40-: {{ageBracketCount(0,40)}}
  <hr />
  <button ng-click="addPerson()">
    Add person
  </button>
</div>

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

Comments

1

You can use a library like lodash: _($scope.people).filter(x => x.age > 18 && x.age <= 25).count()

Alternatively, if you are already using the filtered list in an ng-repeat you can assign it as a variable and get the length e.g.:

<ul>
    <li ng-repeat="item in people | filter:filterFunction as results"></li>
</ul>
<p>{{results.length}}</p>

function filterFunction(item) {
    return item.age > 18 && item.age <= 25;
}

1 Comment

Note, aliasing as is available in Angular 1.3 and greater.

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.