Hi,
I realize that this is a known limitation. Select All will not work across all pages when Remote Paging is enabled; however, this is causing some major problems. Remote Paging is necessary in our situation as we are dealing with more than 10,000 rows. There aren't many cases where we would need to "select all" rows, but "deselecting all" is critical. When a user has a row checked buried within one of the pages it is extremely difficult to find the row that is checked.
I am looking for a solution to this first and foremost. I can try to solve this in a couple ways...
1) I've tried to bind a javascript function to the "select/deselect all" check box so that I could try to programmatically select all rows in the grid DataSource on the client side to no avail. I'd rather not use an external button for aesthetic reasons. Having the "select all" checkbox on top of the column is a natural assumption for the user and there isn't a nice way to hide it. If it is visible the assumption is the user is going to try and use it (to select/deselect all).
2) Is it possible to sort by the "check box" column? I am also using Remote Sorting.
3) Lastly, and this would be most ideal, Is there a way to capture the event of the "select all" checkbox, send the value to the server and set a "Selected" property on the GridDataSource rows? I think this column value could then be used to pprogrammatically select the grid rows in the grid.
Hello Eric,
The second call that selects/deselects the remote ids will, of course, be executed later as it needs to make a remote request to the backend and get the full list of records. Depending on the time needed to process and return the response from the server it is possible for the end-user to change the data in the view (change page, apply filter etc.) and get another view where selection is not yet applied since the request is still pending. You could check if the request is still pending and decide what you want to do in that case ( prevent interactions or allow it and manually select/deselect everything on the new view or something else). Or if the remote data does not change often in your scenario you could get the remote ids once on load and cache them on the client so that you won’t need to make remote calls this often and just update them on actions that change the remote data – like filtering.
For the multiple fast clicks on the checkbox you could simply abort any ongoing remote request initiated from previous clicks and just update the selection once with the latest value, for example:
var remoteReq; function headerRenderedHandler(evt, ui) { … $("#customCheckBox").igCheckboxEditor({ value: false, valueChanged: function (evt, ui) { … if (remoteReq) { remoteReq.abort(); } // get all ids from backend records remoteReq = $.get("@Url.Action("GetIDs")", params, function (data) { for (var i = 0; i < data.length; i++) { $("#Grid").igGridSelection( allSelected ? "selectRowById" : "deselectRowById", data[i]); } ids = data; });
Unfortunately, since selection is currently not stored in the data source (it is stored locally on the client) there’s no simple way to mark the records on the server side as selected/deselected and have that automatically reflected on the client. You would always have to set what is to be selected via the related APIs on the client. You can log a product idea request at: https://ko.infragistics.com/community/ideas so that we may consider implementing Remote Paging with Select All in future versions.
Let me know if there’s anything else I can help you with.
Regards,
Maya Kirova
Update: there was a problem with my code above. When paging then deselecting all it would not deselect properly. Here is my modified code.
// get all ids from backend records var selectedIds = []; selectedIds = $('#grid').igGridSelection('selectedRows').map(function(a) {return a.id;}); $.get("@Url.Action("GetFilteredIDs")", params, function (data) { for (var i = 0; i < data.length; i++) { switch (allSelected){ case true: if(!selectedIds.includes(data[i])) { $("#grid").igGridSelection("selectRowById", data[i]); } break; case false: if(selectedIds.includes(data[i])) { $("#grid").igGridSelection("deselectRowById", data[i]); } break; } } ids = data; });
Maya,
Thank you so much for your help with this. I wouldn't have gotten this far without you. But, I found some additional quirkiness. When I select and unselect the customCheckBox fast (double click) the view rows will select, unselect, then select and unselect again. To clarify, the customCheckBox gets selected once, then unselected once. But, the rows will select twice and unselect twice. I believe this is due to the code calling $("#grid").igGridSelection() twice (In two different loops). Doing it this way does feel a bit awkward. The first loop is selecting the rows of the dataView very fast. I think this is a great solution. However, it appears that the second set of calls to $("#grid").igGridSelection() within the full set of data loop is playing catchup and is slower than my clicks. To fix this I thought not to select the already selected view rows in the second loop like this:
// get all ids from backend records var selectedIds = []; selectedIds = $('#grid').igGridSelection('selectedRows').map(function(a) {return a.id;}); $.get("@Url.Action("GetFilteredIDs")", params, function (data) { for (var i = 0; i < data.length; i++) { switch (allSelected){ case true: if(!selectedIds.includes(data[i])) { $("#grid").igGridSelection("selectRowById", data[i]); } break; case false: if(selectedIds.includes(data[i])) { $("#grid").igGridSelection("deselectRowById", data[i]); } break; }
This appears to help, however the problem still exists initially undetected. If I page through the subsequent pages before the second loop finishes you will see it. I can make this work for now, but this will need to be resolved eventually. I would love to see a solution where I pass the "customCheckBox" value to the server and set the selected rows there on the server. This way there is no client side manipulation and the selected rows are set before the grid gets rendered. Or maybe an api method to select all. I would think this would be widely needed and I'm a bit surprised select all was left out of Remote Paging. I look forward to your thoughts.
Hi ericl,
You could pass the additional request parameters for the remote operations to the request for the ids and since your GridModel is available on the server side you can use its GetData() method that will return the processed data based on the enabled features so that you can get the ids of the currently filtered records only.
Note that in that case, before calling the GetData method paging should be excluded from the GridModel features, so that the result will contain all filtered records, not just the ones on the current page.
For example:
valueChanged: function (evt, ui) { var allSelected = ui.newValue; //get all additional encoded params for remote operations - sorting, filtering etc. var params = $('#Grid').data("igGrid").dataSource._encodeUrl(); $.get("@Url.Action("GetIDs")", params, function (data) {…} }
public ActionResult GetIDs() { //disable paging so that GetData will disregard that feature and return all filtered records (not just the ones on the current page). GridModel m = GetGridModel(false); var filteredData = m.GetData(); List<object> d = ((WrappedGridResponse)filteredData.Data).Records as List<object>; var ids = d.Select(x => (x as Product).ID); JsonResult res = new JsonResult(); res.JsonRequestBehavior = JsonRequestBehavior.AllowGet; res.Data = ids; return res; } public GridModel GetGridModel(bool enablePaging) { … if (enablePaging) { GridPaging p = new GridPaging(); p.Type = OpType.Remote; p.PageSize = 10; model.Features.Add(p); } … }
Regarding the delay for the selection. You could directly select/deselect the rows that are currently in the view so that they will be marked selected/deselected right away. The ones from the remote records will be marked as selected/deselected after the remote request to get their IDs is complete.
valueChanged: function (evt, ui) { var allSelected = ui.newValue; //select/deselect all in the current local data var dataView = $('#Grid').data("igGrid").dataSource.dataView(); for (var i = 0; i < dataView.length; i++) { var rec = dataView[i]; $("#Grid").igGridSelection(allSelected ? "selectRowById" : "deselectRowById", rec.ID); } …
I’ve attached a modified sample for your reference: 7444.Grid_RemotePaging_RemoteFiltering_SelectAll.zip
Let me know if you have any additional questions or concerns regarding this approach.
Thank you so much for your reply. This is a great solution. However; I noticed one problem. If the data is filtered, This still selects all the data. To give you a little more information on my current solution, I am using the GridModel approach instead of the Wrapper.
Another question, there is a bit of a delay after selecting the "select all" checkbox. I am assuming that this is because I have to go to the server to retrieve the Data. Is there a way to improve the performance? Get the data from memory on the client; for example:
var ds = $("#grid1").igGrid("option", "dataSource");
But again, I would need to get only the filtered data.
Thanks again for your help.