In an AngularJS application, I have an ag-grid that uses virtual paging/infinite scrolling to lazy-load rows from a dataset that is too large to show at once. I have turned on check-box selection in the first column, so that the user should be able to select individual rows for arbitrary application-specific actions.
The AngularJS application uses ui-router to control multiple views. So, building on the virtual-paging example with "sorting & filtering", with constructed data about Olympic winners, from the ag-grid
documentation, I've further extended the code a bit. From index.html
:
<body ng-controller="MainController" class="container">
<div ui-view="contents"></div>
</body>
and the following ui-router
states:
myapp.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("example.page1")
$stateProvider
.state('example', {
abstract: true,
views: {
contents: {
template: '<div ui-view="example"></div>'
}
}
})
.state('example.page1', {
url: '/page1',
views: {
example: {
templateUrl: 'page1.html'
}
}
})
.state('example.page2', {
url: '/page2',
views: {
example: {
template: 'Go back to the <a ui-sref="example.page1">example grid</a>.'
}
}
});
});
where page1.html
looks like the following:
<div ng-controller="GridController">
<div ag-grid="gridOptions" class="ag-fresh" style="height: 250px;"></div>
</div>
<div>
<h3>Selected rows:</h3>
<ul class="list-inline">
<li ng-repeat="row in currentSelection track by row.id">
<a ng-click="remove(row)">
<div class="badge">#{{ row.id }}, {{ row.athlete }}</div>
</a>
</li>
</ul>
</div>
<p>Go to <a ui-sref="example.page2">the other page</a>.</p>
What I want to accomplish:
- That selections made in the
ag-grid
is remembered (sticky) when scrolling a (virtual) page out of view and back again, so that a user can select multiple rows on separate pages. - That the remembered selections are available outside the grid, and support adding and removing selections (as intended by the
ng-click="remove(row)"
inpage1.html
, shown above). - That the selections should be remembered when switching from the view with the
ag-grid
to another one, and back again. - (Optional) That the selections are remembered for the user's session.
How can I accomplish this?
I've created a working example of this can be implemented.
First of all, we'll write a AngularJS service,
selectionService
to keep track of the selections:The
selectionService
service allows adding and removing arbitrary objects to separate collections, identified bycollection
, a name you find suitable. This way the same service can be used for remembering selections in multipleag-grid
instances. Each object will be identified using apath
parameter. Thepath
is used to retrieve the unique identifier using lodash's get function.Furthermore, the service uses sessionStorage to persist the selections during the user's whole tab/browser session. This might be overkill; we could have just relied on the service to keep track of the selections since it will only get instantiated once. This can of course be modified to your needs.
Then there were the changes that had to be done to the
GridController
. First of all thecolumnDefs
entry for the first column had to be changed slightlywhere the new, generated row ID is generated once the data has been retrieved from the remote server
(The
'm'
in the ID was included just to make sure I didn't confused that ID with other IDs used byag-grid
.)Next, the necessary changes to
gridOptions
were to addWere the different handlers are quite straight forward, communicating with the
selectionService
Now, the
GridController
needs to handle updates signalled by theselectionService
tooand
calls
selectionService.updateInGridSelections
which will update the in-grid selections of the grid in question. That was the most cumbersome function to write. For example, if a selection has been added externally (outside the grid), then we'll have to perform aforEachNode
run, even if we know all the necessary nodes have already been selected in-grid; there's no way to exit that loop early.Finally, another crux was to clear and reapply the selections before and after, respectively, when the filters or sort orders are changed, or when new data is retrieved from the server (which is only simulated in the demo). The solution was to include a call to
updateSelections
after theparams.successCallback
inside thegetRows
handlerNow, the most puzzling findings during the implementation of this solution was that the
ag-grid
API grid optionsonAfterFilterChanged
andonAfterSortChanged
couldn't be used for reapplying the selections because they trigger before the (remote) data has finished loading.