Pagination GWT DataGrid for Large Data - gwt

I have a case where my DataGrid might contain thousands of rows of data. My page size is only 50. So I want to get only so much data onto the client from server and load rows of data as and when required. Is there a default support from GWT to do that?
I tried using PageSizePager but then realized that the data is already sent to the client and that defeats what am trying to achieve.
Thanks.

Indeed. The aim (among others) of DataGrid, as well as of any other cell widget, is to display large data sets as fast as possible by using pagination and cells.
I suggest you to start with the official docs about CellTable (same applies to DataGrid), and pagination/data retrieval.
You'll probably need an AsyncDataProvider to asynchronously fetch data and an AbstractPager (say, SimplePager) to force retrieval of more data.
You can also decide to extend the current range of rows (say, infinite scroll), instead having multiple pages (by using KeyboardPagingPolicy.INCREASE_RANGE).
In general, the question is too general and can be hardly answered in few lines (or without specify more). The bits are all in the links above, and don't forget to have a look at the cell widgets samples in the showcase, as they cover almost everything you will need.
Hope to get you started.

Related

Is both client and server column filters in ag grid possible?

I want to know if we can do combination filtering in ag grid. Some volumn filtering on client and some on server. is that possible?
I was checking adaptabletools website they have built similar feature with serverOptions.link below. I was trying to achieve similar thing via ag-grid api. Can you please advise
https://api.adaptabletools.com/interfaces/_src_adaptableoptions_searchoptions_.searchoptions.html
Update on this question as I developed AdapTable which the OP refers to in her question.
We DO enable and facilitate server-side searching, sorting and filtering while keeping ag-Grid in ClientSideRowModel mode and many of users take huge advantage of it.
You can learn more at:
https://docs.adaptabletools.com/docs/key-topics/server-functionality
However note that this is suited to the use case where you have a few hundred thousand rows and want to have the best of both worlds; if you have millions of rows of data that needs searching and filtering then you should use ag-Grid's Server or Infinite Row Models (both of which AdapTable fully supports but in different ways to that mentioned in the OP).
Well Client-Side RowModel is the default. The grid will load all of the data into the grid in one go. The grid can then perform filtering, sorting, grouping, pivoting and aggregation all in memory.
The Server-Side Row Model builds on the Infinite Row Model. In addition to lazy-loading the data as the user scrolls down, it also allows lazy-loading of grouped data with server-side grouping and aggregation. Advanced users will use Server-Side Row Model to do ad-hoc slice and dice of data with server-side aggregations.
Ideally developer should choose either of them. Also AG Grid doesn't allow any method to set RowmodelType type programmatically.
So the simple answer is no it can't be done easily.
But I think you can do some workaround by creating another hidden AG Grid which will be created with RowmodelType = 'client side'. update the data in this 2nd grid whenever data changes in the first grid. also switch between grid(using hide show logic) when user wants to filter on client side(may be you can provide a radio button for that) and you can set filterstate/columnstate etc.. settings from 2nd to 1st grid.

free-jqGrid External Filtering Used With Grid's beforeRequest() or onPaging() Event

Using jqGrid free (version 4.15.6) to show very basic information about invoices (ie: date created, date due, client, total, status). The invoices grid only has a few pertinent columns that are displayed because it is just not needed to show more than that. In reality there are a lot of other invoice-related fields that are not shown. I would like to offer end-users the ability to filter the grid based on a lot of these other parameters that are simply not part of the grid contents.
I know jqGrid offers built-in searching, and you can easily just add hidden columns with all the data, but I feel this is not good for us--invoices contain a lot of data--data that is not necessarily present in just the invoices database table. We want the grid to provide many other filtering options outside of the base invoice data but we do NOT want to use the built-in filter options. Instead, I would like to use a separate HTML table with a bunch of search fields that our server-side code would know how to pull back). When one decides to invoke the external filter, we want the grid to load all invoices matching that combined filter. And if one chooses to navigate using the grid's paging buttons, we want the grid to continue using the original external filtering parameters.
Hope this makes sense. Maybe I am just overthinking this but I am fairly certain the grid is designed to use it's built in filtering/searching tools/dialog and I have not found anyway to override this behavior. Actually I have using an older jqGrid but that involved using jQuery to completely REPLACE the default pager with custom HTML and event handling. I never could figure this out with older jqGrid so I chose to write it myself. But that code is less than optimum and even I know it is subject to much criticism. Having upgraded to 4.15.6, I want to do this the best way and I want to keep it logical and practical.
I have tried using beforeRequest() and onPaging() events to change the 'url' parameter, thinking that if I modified the url, I could change the GET to include all of our custom filtering fields. It seems that does not work as the url NEVER changes from the originally defined value. Console logging does show the events firing but no change to url. On top of that, the grid ALWAYS passes its own page field, _search field, etc. to the server so the server NEVER sees the filter request.
How does one define their own custom filtering coupled with paging loader and still take advantage of the built-in paging events? What am I missing?
**** DELETED CODE THAT WAS ADDED TO QUESTION THAT DID NOT PERTAIN TO ORIGINAL QUESTION ISSUE *********
It's difficult to answer on your question because you didn't posted code fragments, which shows how you use jqGrid and because the total number of data, which could be needed to display in all pages isn't known.
In general there are two main alternatives implementing of custom filtering:
server side filtering
client side filtering
One can additionally use a mix from both filtering. For example, one can load from the server all invoices based on some fixed filters (all invoices of specific user or all invoices of one organization, all invoices of the last month) and then use loadonce: true, forceClientSorting: true options to sort and to filter the returned data on the client side. The user could additionally to filter the subset of data locally using filter toolbar of searching dialog.
The performance of client side is essentially improved last years and loading relatively large JSON data from the server could be done very quickly. Because of that Client-Side-Filtering is strictly recommended. For better understanding the performance of local sorting, filtering and paging I'd recommend you to try the functionality on the demo. You will see that the timing of local filtering of the grid with 5000 rows and 13 columns is better as you can expect mostly from the round trip to the server and processing of server side filtering on some very good organized database. It's the reason why I recommend to consider to use client side sorting (or loadonce: true, forceClientSorting: true options) as far it's possible.
If you need to filter data on the server then you need just send additional parameters to the server on every request. One can do that by including additional parameters in postData. See the old answer for additional details. Alternatively one can use serializeGridData to extend/modify the data, which will be set to the server.
After the data are loaded from the server, it could be sorted and filtered locally before the first page of data will be displayed in the grid. To force local filtering one need just add forceClientSorting: true additionally to well known loadonce: true parameter. It force applying local logic on the data returned from the server. Thus one can use postData.filters, search: true to force additional local filtering and sortname and sortorder parameter to force local sorting.
One more important remark about using hidden columns. Every hidden column will force creating DOM elements, which represent unneeded <td> elements. The more DOM elements you place on the page the more slow will be the page. If local data will be used (or if loadonce: true be used) then jqGrid hold data associated with every row twice: once as JavaScript object and once as cells in the grid (<td> elements). Free jqGrid allows to use "additional properties" instead of hidden columns. In the case no data will be placed in DOM of the grid, but the data will be hold in JavaScript objects and one able to sort or filter by additional properties in the same way like with other columns. In the simplest way one can remove all hidden columns and to add additionalProperties parameter, which should be array of strings with the name of additional properties. Instead of strings elements of additionalProperties could be objects of the same structures like colModel. For example, additionalProperties: [{ name: "taskId", sorttype: "integer"}, "isFinal"]. See the demo as an example. The input data of the grid can be seen here. Another demo shows that searching dialog contains additional properties additionally to jqGrid column. The commented part columns of searching shows more advanced way to specify the list and the order of columns and additional properties displayed in searching dialog.
Forgive my answering like this but this question started out on one subject related to filtering and paging but with using an external filtering source. Oleg actually has several demos over many threads that I was able to use to accomplish the custom filtering and maintain default built-in paging. So his answer will be the accepted answer for the original question topic.
But in the solution of original, I encountered another issue with loading the grid initially. I wanted to have the grid load with default filtering values should no other filter already be in place. That really should have been a different question because it really did not affect the first.
I found yet another Oleg reply on a completely different question:
jqGrid - how to set grid to NOT load any data initially?.
Oleg answered that question and that answer solved our second need to load one way, then allow another way.
So, on initial load, we look for the filter params server-side. None given? We pull records using default filtering. Params present? We use initial provided params. The difference with initial loading we do not AJAX exit. We instead json_encode the data and place it in the grid definition as follows:
$('#grd_invoices').jqGrid(
...
url: '{$modulelink}&sm=130',
data: {$json_encoded_griddata},
datatype: 'local',
...
});
Since the datatype is set to 'local', the grid does NOT go to server initially, so the data parameter is used by the grid. Once we are ready to filter, we use Oleg's solution from yet another answer on yet another question to dynamically apply the filter as follows:
var myfilter = { groupOp: 'AND', rules: []};
myfilter.rules.push({field:'fuserid',op:'eq',data:$('#fuserid').val()});
myfilter.rules.push({field:'finvoicenum',op:'eq',data:$('#finvoicenum').val()});
myfilter.rules.push({field:'fdatefield',op:'eq',data:$('#fdatefield').val()});
myfilter.rules.push({field:'fsdate',op:'eq',data:$('#fsdate').val()});
myfilter.rules.push({field:'fedate',op:'eq',data:$('#fedate').val()});
myfilter.rules.push({field:'fwithin',op:'eq',data:$('#fwithin').val()});
myfilter.rules.push({field:'fnotes',op:'eq',data:$('#fnotes').val()});
myfilter.rules.push({field:'fdescription',op:'eq',data:$('#fdescription').val()});
myfilter.rules.push({field:'fpaymentmethod',op:'eq',data:$('#fpaymentmethod').val()});
myfilter.rules.push({field:'fstatus',op:'eq',data:$('#fstatus').val()});
myfilter.rules.push({field:'ftotalfrom',op:'eq',data:$('#ftotalfrom').val()});
myfilter.rules.push({field:'ftotal',op:'eq',data:$('#ftotal').val()});
myfilter.rules.push({field:'fmake',op:'eq',data:$('#fmake').val()});
myfilter.rules.push({field:'fmodel',op:'eq',data:$('#fmodel').val()});
myfilter.rules.push({field:'fserial',op:'eq',data:$('#fserial').val()});
myfilter.rules.push({field:'fitemid',op:'eq',data:$('#fitemid').val()});
myfilter.rules.push({field:'ftaxid',op:'eq',data:$('#ftaxid').val()});
myfilter.rules.push({field:'fsalesrepid',op:'eq',data:$('#fsalesrepid').val()});
var grid = $('#grd_invoices');
grid[0].p.search = myfilter.rules.length>0;
$.extend(grid[0].p.postData,{filters:JSON.stringify(myfilter)});
$('#grd_invoices').jqGrid('setGridParam',{datatype:'json'}).trigger('reloadGrid',[{page:1}]);
This allows us to have the grid show initial data loaded locally, and then subsequent filtering changes the grid datatype to 'json', which forces the grid to go to server with new filter params where it loads the more specific filtering.
Credit goes to Oleg because I used many of his posts from many questions to reach the end result. Thank you #Oleg!

Manually Setting rowCount in GWT DataGrid with a ListDataProvider does not work?

I am using a DataGrid together with a ListDataProvider to display various row data in my application. For most cases, it was fine to fetch everything from the server at once.
Now, it appears to be necessary to fetch data on pagination steps. This means, my RPC call returns 10 items each time and the total count of possible results.
The total count is used to setup the attached SimplePager by manually calling datagrid.setRowCount(totalCount, true) after having set the row data. After is important here,
because setRowData also triggers a setRowCount call with the concrete number of items (always 10 in my case).
The problem is that after having set the row count manually, another participant, a ScheduledCommand triggers a flushCommand which in turn triggers a setRowCount call which
sets the count back to 10. The consequence: the pager shows 1-10 of 10 and the pager controls are disabled.
How can I enforce a certain rowCount even if the ListDataProvider only has 10 items each time?
You might suggest to use an AsyncDataProvider. However, there already is a quite complex generic design (AbstractTablePresenter<DTO, ...> implementing all the logic to fetch data and push it to a generic display)
which is backed by ListDataProviders. Hard to explain, but actually, I would prefer keep using the ListDataProvider.
For my usecase, the easiest fix was to subclass my AbstractTablePresenter for the on-demand case and use an AsyncDataProvider which brings all the features I need. The hurts concerning my design was less heavy than expected (knocking on my shoulders ;-) ).
Tried to subclass ListDataProvider first but the relationship of data, rowCount, rowCountEvents and the attached pager objects is so manifold that you would end up overriding most of the methods of ListDataProvider and your pager implementation.

Backoffice java client framework - load on deman

We are building our new Next generation server for a medium sized back office application.
We already decided we would like to use a java framework for the client side (gwt \ vaadin \ zkoss)
What we would like now is to create a Proof Of Concept example of each technology.
our back office ui is pretty standard, we have tables \ grids with filters that should show entries straight from the DB.
Problem is we got huge amount of rows in each table (1M minimum)
which mean that we must use a load on demand tables for them.
My questions is: how do i implement a load on demand table for my big tables? I looked around and saw the following concept again and again:
you create a container, you populate it with data, the data is being displayed on the client side.
problem is i tried this naive way to populate the containers with 1M entries and it was awful. are there any built in on demand containers?>
any code examples \ references will be a huge help!
You would want to use GWT Cell Table, which has the AsyncDataProvider, that lets you handle the user's paging and sorting events by grabbing data from your server.
It also provides an alternative ListDataProvider, which lets you grab your data as a list of objects, then set that data to your table. If you use ListDataProvider, you have to define how to sort your objects with Comparators, and table will handle sorting and paging against that list.
Google "gwt celltable asyncdataprovider example" for more examples and tutorials.
Vaadin has a nice concept of lazy loading data in most of the components.
For example the table, list, dropdown's etc. have that concept.
The only thing you realy need to know at start, is the number of total rows.
Everything else can then be handled "ondemand".
For example the Table component initially only loads about 30 rows (can be customized)
and then fetches rows as needed. (Or better they are usually fetched just before the user scrols to the next rows)
A example is this demo
http://demo.vaadin.com/dashboard/#!/transactions
How you retrieve the data from your backend depends on the technology used.
But vaadin has working concepts where you don't need to load all 1mio. rows into memory,
it will handle the "fetch on demand" as the rows need to be displayed.

Handling large amount of data in GWT ListBox

I must do a RPC call when my Presenter is revealled. That call result in a String[] with large amount of data. But this call is very very slow. It takes about 1min to finish.
After some tests, i discovered that ListBox.addItem() takes over 30% of this call. It's a huge time for just add String on that Widget.
What can I do to minimize this time?
Assuming that i need to load everything when my Presenter reveal.
Things that I've already done:
Put my Query inside a View(Doesn't affect too much)
Server read a Txt file instead of call DB(worst then View).
Use Collections classes ArrayList,Vector...(Vector reduced time by 5%)
I've noticed that GWT designed a LightweightCollections to improve use of Collections on Client side(It's my next step).
But what can I do about ListBox?
Too much choice is no choice.
You will not be able to tune up GWT Listbox/ValueListBox for purpose of displaying such huge amount data ( i am guessing entries in 1000's considering 20 seconds i.e 30% of 1 min). GWT Listbox is meant for selection. You cannot expect user to see 1000's of values , scroll and then select. Its a User Interaction nightmare.
The right approach is use to Async loaded SuggestBox for such huge data. With SuggestBox you can filters and display lesser data as choice based on users input keys.
If using SuggestBox is not feasible you must give a try for CellList in Cell Widgets ( they might show better performance ) - https://developers.google.com/web-toolkit/doc/latest/DevGuideUiCellWidgets
I am not sure but give GWTChosen a try - http://jdramaix.github.com/gwtchosen/