Getting the number of results from a filtered, ordered ng-repeat

The best way to return the number of results from a filtered ngRepeat (ordered or not) is by assigning an alias to it.

Let’s say we have a list of books. We use ngRepeat to output the list like so:

<ul>
    <li ng-repeat="book in books">
        <p>{{book.title}}</p>
    </li>
</ul>

At this point, returning the total number of books in our list would be as simple as referencing {{books.length}} in our document.

But maybe we have a lot of books on our list, so we add an input field to our document where our user can enter search criteria to narrow it down, as well as a filter to our ngRepeat, based on their input:

<!-- Here's our input field: -->
<input type="text" ng-model="search">

<!-- And here's our now-filtered book list: -->
<ul>
    <li ng-repeat="book in books | filter:search">
        <p>{{book.title}}</p>
    </li>
</ul>

So how do we get the number of books returned by our filter? We could execute the filter again, wherever in our document we wanted to output the information:

<p>Total results: {{ ( books | filter:search ).length }}</p>

But this is the very definition of WET. There’s absolutely no reason to execute the same filter on the same data set on the same page a second time.

Unless, of course, you just really love typing.

Instead, we assign an alias to our filtered result in the ngRepeat line, like so:

<li ng-repeat="book in results = ( books | filter:search )">

Referencing the number of books returned by our filter is as simple as calling {{results.length}} in our document.

Note: As of Angular 1.3, one can also use an filter:expression as alias_expression construction in the ngRepeat to assign an alias, like so:

<li ng-repeat="book in books | filter:search as results">

The reference would be the same: {{results.length}}

Now, if we wanted to enable the user to sort the filtered results, we would add a dropdown of sort criteria, then reference it in our ngRepeat using orderBy, like so:

<!-- Our search field -->
<input type="text" ng-model="search">

<!-- Our sort dropdown: -->
<select ng-model="order">
    <option value="title">Sort by title</option>
    <option value="author">Sort by author</option>
</select>

<!-- Our filtered, sorted book list -->
<ul>
    <li ng-repeat="book in books | filter:search | orderBy:order">
        <p>{{book.title}}</p>
    </li>
</ul>

In order to reference the results (without executing the filter a second time, like some sort of nihilist) we again assign an alias, like so:

<li ng-repeat="book in results = ( books | filter:search | orderBy:order )">

No, we don’t need the orderBy in order to get the number of results (referenced, as before, with {{results.length}}) but we do need it in order to output our results in the selected order.