I have a data array which contains many objects (JSON format). The following can be assumed as the contents of this array:
var data = [
{
"name": "Jim",
"age" : 25
},
{
"name": "Jerry",
"age": 27
}
];
Now, I display these details as:
<div ng-repeat="person in data | filter: query">
</div
Here, query is modeled to an input field in which the user can restrict the data displayed.
Now, I have another location in which I display the current count of people / person being display, i.e Showing {{data.length}} Persons
What I want to do is that when the user searches for a person and the data displayed is filtered based on the query, the Showing...persons
also change the value of people being shown currently. But it is not happening. It always displays the total persons in data rather than the filtered one - how do I get the count of filtered data?
For Angular 1.3+ (credits to @Tom)
Use an alias expression (Docs: Angular 1.3.0: ngRepeat, scroll down to the Arguments section):
<div ng-repeat="person in data | filter:query as filtered">
</div>
For Angular prior to 1.3
Assign the results to a new variable (e.g. filtered
) and access it:
<div ng-repeat="person in filtered = (data | filter: query)">
</div>
Display the number of results:
Showing {{filtered.length}} Persons
Fiddle a similar example. Credits go to Pawel Kozlowski
For completeness, in addition to previous answers (perform calculation of visible people inside controller) you can also perform that calculations in your HTML template as in the example below.
Assuming your list of people is in data
variable and you filter people using query
model, the following code will work for you:
<p>Number of visible people: {{(data|filter:query).length}}</p>
<p>Total number of people: {{data.length}}</p>
{{data.length}} - prints total number of people
{{(data|filter:query).length}} - prints filtered number of people
Note that this solution works fine if you want to use filtered data only once in a page. However, if you use filtered data more than once e.g. to present items and to show length of filtered list, I would suggest using alias expression (described below) for AngularJS 1.3+ or the solution proposed by @Wumms for AngularJS version prior to 1.3.
New Feature in Angular 1.3
AngularJS creators also noticed that problem and in version 1.3 (beta 17) they added "alias" expression which will store the intermediate results of the repeater after the filters have been applied e.g.
<div ng-repeat="person in data | filter:query as results">
<!-- template ... -->
</div>
<p>Number of visible people: {{results.length}}</p>
The alias expression will prevent multiple filter execution issue.
I hope that will help.
{{(data|filter:query|filter:query2).length}}
The easiest way if you have
<div ng-repeat="person in data | filter: query"></div>
Filtered data length
<div>{{ (data | filter: query).length }}</div>
ngRepeat creates a copy of the array when it applies a filter, so you can't use the source array to reference only the filtered elements.
In your case, in may be better to apply the filter inside of your controller using the $filter
service:
function MainCtrl( $scope, filterFilter ) {
// ...
$scope.filteredData = myNormalData;
$scope.$watch( 'myInputModel', function ( val ) {
$scope.filteredData = filterFilter( myNormalData, val );
});
// ...
}
And then you use the filteredData
property in your view instead. Here is a working Plunker: http://plnkr.co/edit/7c1l24rPkuKPOS5o2qtx?p=preview
{{filteredData.length}}
instead of data.length
. I also understood that myInputModel
is the model mapped to the input query which filters the data. val
would be the text that is typed in the input (basically query) but each time I type, it changes. But what is filterFilter
here? I might add that I have my own customFilter created (wherein I can specify which key of the object to consider for filtering).
ng-repeat="person in filteredData"
as there is no sense filtering it twice. With the $filter
service, you can ask for a specific filter by just suffixing it with "Filter", e.g.: dateFilter
, jsonFilter
, etc. If you are using your own custom filter, just use that one instead of the generic filterFilter
.
Since AngularJS 1.3 you can use aliases:
item in items | filter:x as results
and somewhere:
<span>Total {{results.length}} result(s).</span>
From docs:
You can also provide an optional alias expression which will then store the intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message when a filter is active on the repeater, but the filtered result set is empty. For example: item in items | filter:x as results will store the fragment of the repeated items as results, but only after the items have been processed through the filter.
$scope.$watch
to this aliased result. Any tips for $broadcast
ing the aliased results
variable?
It is also useful to note that you can store multiple levels of results by grouping filters
all items: {{items.length}}
filtered items: {{filteredItems.length}}
limited and filtered items: {{limitedAndFilteredItems.length}}
<div ng-repeat="item in limitedAndFilteredItems = (filteredItems = (items | filter:search) | limitTo:25)">...</div>
here's a demo fiddle
Here is worked example See on Plunker
<body ng-controller="MainCtrl">
<input ng-model="search" type="text">
<br>
Showing {{data.length}} Persons; <br>
Filtered {{counted}}
<ul>
<li ng-repeat="person in data | filter:search">
{{person.name}}
</li>
</ul>
</body>
<script>
var app = angular.module('angularjs-starter', [])
app.controller('MainCtrl', function($scope, $filter) {
$scope.data = [
{
"name": "Jim", "age" : 21
}, {
"name": "Jerry", "age": 26
}, {
"name": "Alex", "age" : 25
}, {
"name": "Max", "age": 22
}
];
$scope.counted = $scope.data.length;
$scope.$watch("search", function(query){
$scope.counted = $filter("filter")($scope.data, query).length;
});
});
You can do it with 2 ways. In template and in Controller. In template you can set your filtered array to another variable, then use it like you want. Here is how to do it:
<ul>
<li data-ng-repeat="user in usersList = (users | gender:filterGender)" data-ng-bind="user.name"></li>
</ul>
....
<span>{{ usersList.length | number }}</span>
If you need examples, see the AngularJs filtered count examples/demos
Success story sharing
$scope.filtered.length
.undefined
, likely because at the time of logging it, the variable isn't defined yet. So how would I ensure the code in the controller is run after the variable was defined and the filter was applied in the view?$scope.$watch('filtered', function() { console.log('filtered:', $scope.filtered); });
person in data | filter:query as filtered | limitTo:5
. So I had to use the prior to 1.3 version:person in filtered = (data | filter: query) | limitTo: 5