Pager starts to change pages back and forth when clicking page links fast - gwt

I have a Pager extended from AbstractPager in which every time on range or row count changed I recreate NavLinks contained in it so pager looks like this:
1 2 3 … N-1 N N+1 … M-2 M-1 M
My algorithm works fine but when I start clicking on links fast (like really furiously) by the time one RangeChange event is performing (CellTable to which my pager is attached shows spin trying to fetch data on given page) there's already another ones coming to the EventBus. It results in changing current page back and forth in an infinite loop.
I tried to make paging links enabled only when current page is competely fetched by using Scheduler.get().scheduleDeferred and .scheduleFinally but with no luck.
My temporary solution is to enable paging links after 500 ms by using Scheduler.get().scheduleFixedDelay(), but I want to know how to get the exact moment of data on the current page being fully fetched.
Thanks.

If you have the same problem you need to hang LoadingChangeEvent.Handler on your CellTable, check if data is fully loaded and inform pager about it so pager can activate it's NavLinks:
pager.setDisplay(cellTable);
cellTable.addLoadingStateChangeHandler(new LoadingStateChangeEvent.Handler() {
#Override
public void onLoadingStateChanged(LoadingStateChangeEvent event) {
if (event.getLoadingState() == LoadingStateChangeEvent.LoadingState.LOADED) {
pager.activateNavLinks();
};
}
});
There's no way to do it internally in your pager since setDisplay() accepts HasRows and addLoadingStateChangeHandler() is in AbstractHasData (AbstractHasData implements HasData, HasData implements HasRows).

Related

GWT SimplePager issues

I am using GWT's (2.5) SimplePager class in my application, to display pre-loaded data (I know the exact row count in advance).
The issue is with the last page. Given I have, for instance, 42 elements with an initial visible range of 10.
First page is 1-10, second 11-20, third 21-30, fourth, 31-40.
The issue is that fifth page is not 41-42 (which I want, because I want to be able to scroll back and forth and "land" exactly on the same data) but 33-42.
I have tried various tinkering with overriding SimplePager / AbstractPager methods, with no success.
For instance, if I override setPageStart, do the same as com.google.gwt.user.cellview.client.AbstractPager.setPageStart(int) but with the following commented out (I think it is the culprit code):
if (isRangeLimited && display.isRowCountExact()) {
index = Math.min(index, display.getRowCount() - pageSize);
}
The last page is fine (41-42), but this erases page size forever and when I go from last page to previous page, it becomes 40-41 (expected: 31-40). This is probably because the page size is not some constant provided to the pager instance, but is calculated with the Range object which was last used ("int pageSize = range.getLength();" in setPageStart method).
Any clue on modifying the paging behavior to my needs without breaking anything ?
Thanks !
I eventually got a working solution which is simple enough.
I provided a page size (which is the maximum number of elements that could be displayed, regardless of the total number of elements available to display) to my SimplePager object. Then I overrided getPage(), hasNextPage(), hasNextPages(int), hasPreviousPages(int), nextPage(), previousPage(), setPageStart(int) to use the provided page size instead of getLength() on the Range object.
To test this more easily (still done by hand...) I used GWT's Showcase project (and ran it in dev mode).
The downside is that I had to copy the code of the overriden methods (from AbstractPager - SimplePager does nothing except calling the superclass' methods) into my Pager class.

GWT Detect DOM changes or modifications

What am I trying to do?
I have an existing page (generated by system automatically and I don't have any control on it) in which I am injecting GWT code to modify the behaviour of the page after it loads based on certain columns and augment the functionality of the page. For example after adding my GWT code, cells in one of the table columns become clickable and when the user clicks it, additional information is displayed to the user in a pop-up panel. All that is working fine.
What is the issue?
The generic page in which I am injecting my code has paginated table which shows 15 rows at a time. Now, when I load/refresh the page, my GWT code kicks in and sinks events in the specific column which adds functionality (described above) to the cells. However, when the user uses the left and right buttons to navigate the paginated result, the page does not refresh as it is an asynchronous call. The specific column in the new set of 15 rows is now without the sunk events as the GWT code does not know that the page changed.
I am trying to find a way to tell my GWT code that page has changed and it should sink events to the cells of specific column for the new 15 rows but unable to find any method or mechanism to help me capture a DOM/Document change event. I tried doing this but did not help:
new ChangeHandler(){
#Override
public void onChange(ChangeEvent event) {
Window.alert("Something Changed");
}
It is possible I am missing something very obvious. Posting this question to know if there is an easy way to figure out DOM changes in GWT. Have searched for DOM/Document change/mutation/ etc. without luck.
If anyone knows how to detect DOM changes in GWT would really appreciate otherwise would go ahead writing native code using native mutation observers.
You can try something like this:
First get the input elements with:
InputElement goOn = DOM.getElementById("IdOfGoOnButton").cast();
InputElement goBack = DOM.getElementById("IdOfGoBackButton").cast();
Next add a native EventHandler:
Event.addNativePreviewHandler(new Event.NativePreviewHandler() {
#Override
public void onPreviewNativeEvent(Event.NativePreviewEvent event) {
if (event.getTypeInt() == Event.ONCLICK) {
if (event.getNativeEvent()
.getEventTarget() != null) {
Element as = Element.as(event.getNativeEvent()
.getEventTarget());
if (as.getTagName()
.toLowerCase()
.equals("input")) {
InputElement clickedElement = as.cast();
if (clickedElement.getId().equals(goOn.getId()) ||
clickedElement.getId().equals(goBack.getId())) {
// one of the paging button is pressed
}
}
}
}
}
});
Hope that helps.

Preserve the scroll position of a Page

I have a page with many elements (forms and tables)
When I want add a row in a table I scroll the page to the table, I press a button to add a row, edit the info in a popup and press OK.
Then I insert the new row in the model and refresh() the model.
At this point the page auto scroll at the top, but I don't want this behavior!
I want that the page stay in the same Y position!
I see that sap.m.page has scrollTo function https://openui5.hana.ondemand.com/docs/api/symbols/sap.m.Page.html#scrollTo
but I don't know how take the position before the refresh()
The Page does unfortunately not have an API to get the current scroll position, but the idea is a good one we consider.
As a workaround you could access some private method of the Page - but only if you accept the risk that it breaks with a future version of UI5:
page.getScrollDelegate().getScrollTop()
To make it safer you should verify both methods exist before calling them and also check the returned value for plausibility. Then you are pretty safe that in the worst case it will again scroll to the top in some future UI5 version.
you have to fill the iTime parameter in scrollTo function - e.g. srollTo(100, 1) - then it works
using 0 for iTime does not work

GWT 2.4 DataGrid automatic scrolling when selecting an item

I am using GWT 2.4's new DataGrid in a project. I configured the DataGrid with a pagesize of 50.
The available screen is not big enough to display all items and thus a vertical scrollbar is shown (this is actually the main purpose for using a DataGrid in the first place).
I attached a SingleSelectionModel to the DataGrid in order to be able to select items.
This works fine so far.
However I also have another widget with which the user can interact. Based on that user action a item from the DataGrid should be selected.
Sometimes the selected item is not in the visible screen region and the user has to scroll down in the DataGrid to see it.
Is there any way to automatically or manually scroll down, so that the selected item is visible?
I checked the JavaDocs of the DataGrid and found no appropriate method or function for doing that.
Don't know if this works, but you could try to get the row element for the selection and use the scrollIntoView Method.
Example Code:
dataGrid.getRowElement(INDEX_OF_SELECTED_ITEM).scrollIntoView();
The answer above works pretty well, though if the grid is wider than your window and has a horizontal scroll bar, it also scrolls all the way to the right which is pretty annoying. I was able to get it to scroll down and stay scrolled left by getting the first cell in the selected row and then having it scroll that into view.
dataGrid.getRowElement(dataGrid.getVisibleItems().indexOf(object)).getCells().getItem(0).scrollIntoView();
Don't have time to try it out, but DataGrid implements the interface HasRows, and HasRows has, among other things, a method called setVisibleRange. You just need to figure out the row number of the item that you want to focus on, and then set the visible range from that number n to n+50. That way the DataGrid will reset to put that item at the top (or near the top if it is in the last 50 elements of the list backing the DataGrid). Don't forget to redraw your DataGrid.
Have you already looked at this? If so, I'd be surprised that it didn't work.
Oh, and since this is one widget talking to another, you probably have some messaging set up and some message handlers so that when the user interacts with that second widget and "selects" the item, the message fires on the EventBus and a handler for that message fixes up the DataGrid along the lines I've described. I think you'll have to do this wiring yourself.
My solution, a little better:
dataGrid.getRow(model).scrollIntoView();
I got a Out of bounds exception doing the above.
I solved it getting the ScrollPanel in the DataGrid and used .scrollToTop() and so on on the ScrollPanel. However, to access the ScrollPanel in the DataGrid I had to use this comment:
http://code.google.com/p/google-web-toolkit/issues/detail?id=6865
As Kem pointed out, it's annoying the "scrollToRight" effect after the scrollIntoView. After me, Kem's solution gives a better behaviour than the base one as usually the first columns in a table are the more meaningful.
I improved a bit his approach, which scrolls horizontally to the first column of the row we want to be visible, by calculating the first visible column on the left before applying the scroll and then scrolling to it.
A final note: Columns absolute left is tested against "51". This is a value I found "experimentally" by looking the JS values in the browser's developer tool, I think it depends on the table's style, you may need to change/calculate it.
Below the code:
public void scrollIntoView(T next) {
int index = datagrid.getVisibleItems().indexOf(next);
NodeList<TableCellElement> cells = datagrid.getRowElement(index).getCells();
int firstVisibleIndex = -1;
for(int i=0; i<cells.getLength() && firstVisibleIndex<0;i++)
if(UIObject.isVisible(cells.getItem(i)) && (cells.getItem(i).getAbsoluteLeft() > 51) && (cells.getItem(i).getAbsoluteTop() > 0))
firstVisibleIndex = i;
cells.getItem(firstVisibleIndex>=0? firstVisibleIndex : 0).scrollIntoView();
}

Do GWT CEllTables have a 15 row limit?

I have a little piece of code which populates a CellTable from a
Type by adding the table as a DataProviders DataDisplay and by
using the DataProviders list to create a ColumnSortHandler and
corresponding Comparators... so each time the user clicks next I
populate the table in this manner with the next set of data. It all
works great apart from when the number of elements in my set of data
is greater than 15. In this case only the top 15 (ordered) elements
are displayed I.E. only 15 rows of the CellTable are visible within
the VerticalDialog. Is this a default somewhere or can I configure
this row limit. I've looked around my code and I can see places where
I have instantiated a list and this will default to 10 elements but 15
has me baffled.
I can provide code but thought this would jog a memory without the
need for boring old code.
Many thanks
Tony
This is a default yes: http://google-web-toolkit.googlecode.com/svn/javadoc/latest/com/google/gwt/user/cellview/client/CellTable.html#CellTable()
Constructs a table with a default page size of 15.
You can change it at any time with setPageSize or setVisibleRange.
Adding to Thomas Broyer answer. I always use the code below passing my CellTables/CellLists when I don't want pagination.
public static void setupOnePageList(final AbstractHasData<?> cellTable) {
cellTable.addRowCountChangeHandler(new RowCountChangeEvent.Handler() {
#Override
public void onRowCountChange(RowCountChangeEvent event) {
cellTable.setVisibleRange(new Range(0, event.getNewRowCount()));
}
});
}