Basically, the problem was that the controller was doing what you knew could be accomplished inside of the view... what made this more difficult than most other cases was that you're trying to paginate the same data that you're filtering and displaying the length... so this means that your data must be manipulated in this order:
- filtered data based on search item
- capture the length of the filtered items
- paginate the filtered items and display
The first thing that I know had to be done was rework the ng-repeat
to do the filtering. The goal was to use that build in angular filtering.
Originally, it looked like this. Which did the filtering AND the paging, but used custom code in the controller.
data-ng-repeat="statement in pagedStatementData()"
Step 1: Use the angular filter
The filtering that you posted in your question was an easier way to do this without writing custom filtering code... so that was my first step. Easy enough.
data-ng-repeat="statement in statements | filter:statementFilter"
Step 2: Get pagination back
At this point, the list is filtered correctly, but displays all of the filtered items and does not break them into pages. The pagination buttons work as they should and the total records update accordingly. So now the next step is to insert that pagination into this filtered list.
In the script, I added begin and end to the scope. These variables were previously created inside of the pagedStatementData()
. Then using those values, I can slice the filtered array to get the pagination going.
Note: This $scope.begin $scope.end code was eventually removed in Step 5, because it's only calculated on the initial render and didn't update after then. It was a bug I didn't notice until Step 5.
$scope.begin = ($scope.currentPage-1)*$scope.numPerPage;
$scope.end = ($scope.begin + $scope.numPerPage);
data-ng-repeat="statement in (statements | filter:statementFilter).slice(begin, end)"
Step 3: Remove controller code that is not wanted/needed
At this point, everything works... but the goal is to remove the custom filtering code... so I removed the $scope.filteredStatementData
method and the $scope.totalFilteredStatementItems
method that called it. $scope.pagedStatementData
can get deleted also.. that was called in the ng-repeat
that was modified in Step 1.
Removed:
- $scope.filteredStatementData // custom filter code.. removed
- $scope.totalFilteredStatementItems // called filteredStatementData... removed
- $scope.pagedStatementData // this was called by the original ng-repeat... removed
Step 4: Fix total items # and pagination buttons. Both depend on the same .length
At this point... the view is broken, because it's still making a few calls to the methods we just removed. (totalFilteredStatementItems) So now the goal is to replace that functionality with what we have in the view. totalFilteredStatementItems used to run that custom filtering logic and then got the length without paginating the data.
We already have the items being filtered, so we just need to save them to the scope (before they're paginated) so that they can be accessed elsewhere. We can save that filtered array inside of the ng-repeat, actually. As long as the syntax remains item in items
... but items
can be assigned to a scope variable... like item in (items = (/*filter*/)).slice(x,y)
data-ng-repeat="statement in (filteredItems = (statements | filter:statementFilter)).slice(being, end)"
<div>Total records: {{ filteredItems.length }}</div>
<pagination data-ng-model="currentPage" total-items="filteredItems.length"
Okay. That ng-repeat is starting to get crazy, but it's still working. The parens are the real magic here. This code is executed in the desired order.
// filtered data based on search item
$scope.filteredItems = $scope.statements.filter(/*statementFilter magic*/);
// paginate the filtered items
var _temp = filteredItems.slice($scope.begin, $scope.end),
_i, statement;
// display page of filtered items
for (var _i in _temp) {
statement = _temp[_i];
// Render each row w/ statement
}
Also, I'm sure there's some Angular $scope magic going on to update the filteredItems.length since it's used in the Total records:
div before the list is filtered... thanks Angular! Or maybe it prioritizes ng-repeat and executes that block first. Idk. It works.
Step 5: Pagination is broken. Get the pagination component to update begin and end variables that the list depends on.
Deleted $scope.begin and $scope.end code in controller.
Create them inside of ng-init
when the component is first created, and then on the data-ng-change
event, recalculate those values.
<pagination data-ng-model="currentPage" total-items="filteredItems.length"
items-per-page="numPerPage" data-max-size="maxSize" data-boundary-links="true"
ng-init="begin = (currentPage-1)*numPerPage; end = begin + numPerPage"
data-ng-change="begin = (currentPage-1)*numPerPage; end = begin + numPerPage">