1

I have this array of items

[
  {
    name: 'Foo',
    completed: false
  },
  {
    name: 'Ninja',
    completed: true
  },
  {
    name: 'Hello',
    completed: true
  },
  {
    name: 'Baby',
    completed: false
  },
]

I'd like to display the count where completed = true in my view. I also need this counter to update automatically when an element goes from completed=false to true. Is there a way to do this in angular?

0

3 Answers 3

7

You should look about filter and use it to filter dynamically your array; In your controller declare your filter like this

$scope.completedFilter(object) {
    return object.completed === true;
}

After in your template you can just add

{{(myArray | filter:completedFilter).length}}

And your count will be automatically changed with the completed

Note: you can also declare a filter in you module that could be proper if you want to reuse it in another controller

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

2 Comments

Nice idea, but I bet the filter approach has the same performance implications as using $watch with large arrays of items. It all depends on how the filter is implemented, and my guess is that it relies on angular.equals which is a potential performance killer.
or just add it straight in the view as... {{(myArray | filter: { completed : true } ).length}}
0

There are a number of approaches you could take, but they all start by caching the count of the number of items that are completed when the controller loads.

You could use the $watch function to monitor the array, and update a counter when the object changes. The following is untested, but should give you a sense of how to do it

function myCtl($scope, itemFetcher) {
  $scope.items = itemFetcher.get(); //retrieves your array of items
  $scope.numComplete = countComplete();

  $scope.$watch("items", function(newValue, oldValue) {
    $scope.items = newValue;
    $scope.numComplete = countComplete();
  }, true); // NOTE: passing true into $watch is necessary to do a deep compare (i.e. comparing object properties), and I think it is required in this case, but it has a negative impact on performance & memory.

  function countComplete() {
    var cnt = 0;
    angular.forEach($scope.items, function(item) {
      cnt += item.completed ? 1 : 0;
    }
    return cnt;
  }
}

Alternatively, you can update the completed count in functions that modify the items completed state. The following code is also untested.

function myCtl($scope, itemFetcher) {
  $scope.items = itemFetcher.get(); //retrieves your array of items
  $scope.numComplete = countComplete();

  $scope.markItem = function(index, newState) { // this function is referenced in your HTML template
    $scope.items[index].complete = newState;
    $scope.numComplete += (newState) ? 1 : -1;
  }

  function countComplete() {
    var cnt = 0;
    angular.forEach($scope.items, function(item) {
      cnt += item.completed ? 1 : 0;
    }
    return cnt;
  }
}

Using $watch is more convenient and less error-prone, but may cause performance issues depending on the size of the items array. The second approach is more efficient, but tougher to maintain.

Comments

0

Is adding a $watch necessary ?

Try this way

 $scope.itemCount = function () {
    var cnt = 0;
    angular.forEach($scope.items, function (item) {
        cnt += item.completed ? 1 : 0;
        console.log(item);
    });
    return cnt;
}

Just to check the count is getting updated i added an item on button click to items array

$scope.insertItem = function () {
    $scope.items.push({ name: 'Phani', completed: true });

}
{{itemCount()}}

    <input type="button" ng-click="insertItem()" value="Insert" />

Try the above approach

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.